TypeScript generi c параметры типа: T vs T extends {} - PullRequest
1 голос
/ 07 мая 2020

Существует ли функциональная разница между двумя параметрами обобщенного типа c, приведенными ниже?

Ответы [ 3 ]

2 голосов
/ 07 мая 2020

Примечание: я предполагаю, что вы используете версию TypeScript 3.5 или новее; в TypeScript 3.5 было внесено изменение, так что параметры типа generi c неявно ограничены unknown вместо пустого типа объекта {}, а также некоторые незначительные детали о различиях между funcA() и funcB() изменено. Я не хочу делать длинный пост еще более длинным, говоря о том, как все было в TS3.4 и ниже.


Если вы явно не ограничиваете a generi c type через extends XXX, тогда он будет неявно ограничен unknown, «верхним типом», которому могут быть присвоены все типы. Таким образом, на практике это означает, что T в funcA<T>() может быть абсолютно любого типа, который вы хотите.

С другой стороны, тип пустого объекта {} - это тип, для которого почти все типы могут быть присвоены, кроме для null и undefined, когда вы включили параметр компилятора --strictNullChecks (что вам следует) . Даже примитивные типы, такие как string и number, могут быть присвоены {}.

Итак, сравните:

function funcA<T>() { }
funcA<undefined>(); // okay
funcA<null>(); // okay
funcA<string>(); // okay
funcA<{ a: string }>(); // okay

с

function funcB<T extends {}>() { }
funcB<undefined>(); // error
funcB<null>(); // error
funcB<string>(); // okay
funcB<{ a: string }>(); // okay

Единственная разница в что T extends {} запрещает null и undefined.


Это может немного сбивать с толку, что {}, так называемый "объектный" тип, будет принимать примитивы вроде string и number. Это помогает думать о таких окруженных фигурными скобками типах, как {} и {a: string}, а также обо всех типах interface не обязательно как о «истинных» типах объектов, но как о типах значений, в которые вы можете индексировать их, как если бы они были объектами без ошибок времени выполнения. Примитивы, за исключением null и undefined, «объектно-подобны» в том смысле, что вы можете обращаться с ними, как если бы они были обернуты их эквивалентами объекта :

const s: string = "";
s.toUpperCase(); // okay

И поэтому даже примитивы, такие как string, могут быть присвоены типам, заключенным в фигурные скобки, если члены этих типов совпадают:

const x: { length: number } = s; // okay

Если вам действительно нужен express тип, который принимает только «true», например, не примитивные объекты, вы можете использовать object:

const y: object & { length: number } = s; // error
const z: object & { length: number } = { length: 10 }; // okay

Но я (серьезно) отклоняюсь.


Хорошо, надеюсь, что это поможет; удачи!

Детская площадка ссылка на код

1 голос
/ 07 мая 2020

Да. В funcB T должен расширять {}, что означает почти все, кроме null и undefined . Хотя T может быть примитивом.

0 голосов
/ 07 мая 2020

Следующее должно указывать общий c параметр, в следующем случае используется для указания параметра типа, который может принимать функция:

function funcA<T>(t: T) { }

вы можете использовать его, чтобы указать, какой тип функция возвращает следующее:

function funcA<T>() T {}

С другой стороны, T extends Something означает, что функция может принимать любой параметр, расширяющий Something. Допустим, у нас есть интерфейс Person и некоторые другие интерфейсы, которые реализуют Person, например, Teacher, Student, мы можем написать функцию:

function funcA<T extends Person>(t: T)

мы можем вызвать funcA только с параметр, расширяющий T.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...