Динамичное переопределение Symbol.toPrimitive
Описание
Написал простой класс, в нем динамичное переопределение Symbol.toPrimitive
:
interface PrimitiveHintsMap {
"number": number;
"boolean": boolean;
"string": string;
}
class Timespan {
#duration = 0;
[Symbol.toPrimitive]<K extends keyof PrimitiveHintsMap>(hint: K): PrimitiveHintsMap[K] {
switch (hint) {
case `number`: return this.#duration;
case `boolean`: return Boolean(this.#duration);
case `string`: return this.toString();
default: throw new TypeError(`Invalid '${hint}' primitive hint`);
}
}
}
... так же как это сделано для встроенных слушателей DOM:
Функция жалуется при каждом return
, что
Type 'number' is not assignable to type 'PrimitiveHintsMap[K]'.
Type 'number' is not assignable to type 'never'.ts(2322)
Вопрос
Где я допускаю ошибку?
Откуда вообще тут нашлась never
?
Ответы (1 шт):
Где я допускаю ошибку?
Нигде. В таких сложных местах ts не может понять тип, поэтому надо кастить явно.
Впрочем, меня смущают строки в switch в косых кавычках - я бы побоялся, что они мешают вывести нужные ограничения, но в твоём случае прямые кавычки не помогают.
Откуда вообще тут нашлась
never
?
Это пересечение всех значений PrimitiveHintsMap
, т. е. number & boolean & string
- это never
.
При особом желании касты можно заменить на перегрузку функции, но по сути она просто убивает часть проверок типов, поэтому, вероятно, я бы делал через каст.
interface PrimitiveHintsMap {
"number": number;
"boolean": boolean;
"string": string;
}
class Timespan {
#duration = 0;
[Symbol.toPrimitive]<K extends keyof PrimitiveHintsMap>(hint: K): PrimitiveHintsMap[K];
[Symbol.toPrimitive]<K extends keyof PrimitiveHintsMap>(hint: K): PrimitiveHintsMap[keyof PrimitiveHintsMap] {
switch (hint) {
case 'number': return this.#duration;
case 'boolean': return Boolean(this.#duration);
case 'string': return this.toString();
default: throw new TypeError(`Invalid '${hint}' primitive hint`);
}
}
}