Перейти к содержанию

Конкретизация типа для обобщений

Скажем, у вас есть что-то, например класс Foo, который имеет обобщённый параметр:

1
2
3
class Foo<T> {
    foo: T;
}

Вы хотите создать для него уточнённую версию для определенного типа. Паттерн состоит в том, чтобы скопировать элемент в новую переменную и дать ей описание типа с заменой обобщённых типов конкретными типами. Например, если вам нужен класс Foo<number>:

1
2
3
4
class Foo<T> {
    foo: T;
}
let FooNumber = Foo as { new (): Foo<number> }; // ссылка 1

В ссылке 1 вы говорите, что FooNumber это то же самое, что Foo, но просто относитесь к нему как к чему-то, что при вызове с оператором new дает экземпляр Foo<Number>.

Наследование

Паттерн утверждения типа небезопасен, поскольку он доверяет вам сделать всё правильно. Распространенный паттерн в других языках для классов - просто использовать наследование:

1
class FooNumber extends Foo<number> {}

Одно предостережение: если вы используете декораторы в базовом классе, то унаследованный класс может не иметь того же поведения, что и базовый класс (он больше не обёрнут декоратором).

Даже если вы не уточняете свои классы, вам все равно нужно придумать паттерн приведения / утверждения, который работает, для начала покажем общий шаблон утверждения, например:

1
2
3
4
function id<T>(x: T) {
    return x;
}
const idNum = id as { (x: number): number };

Меня вдохновил этот вопрос на stackoverflow

Комментарии