下面的两个泛型类型参数在功能上是否有区别?
sum()
我看到它们都被使用了并且对它们的区别感到困惑吗?
答案 0 :(得分:3)
注意:我假设您使用的是TypeScript 3.5或更高版本。在TypeScript 3.5中进行了更改,因此generic type parameters are implicitly constrained by unknown
instead of the empty object type {}
以及有关funcA()
和funcB()
之间的区别的一些次要详细信息已更改。我不想通过谈论TS3.4及以下版本中的情况来写更长的篇幅。
如果没有通过extends XXX
显式地constrain泛型类型参数,则它将隐式地受unknown
约束,{所有类型都可以分配给该类型的“顶部类型”。因此,实际上,这意味着T
中的funcA<T>()
可以是您想要的任何类型。
另一方面,空对象类型{}
是所有类型都可以分配给 的类型,{{ 1}}和null
(应启用--strictNullChecks
compiler option)。甚至undefined
和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}
类型不一定视为“ true”对象类型,而是将其视为值类型可以像它们是对象一样索引它们,而不会出现运行时错误。 interface
和null
以外的基元是“类对象”,因为您可以将它们视为wrapped with their object equivalents:
undefined
因此,即使const s: string = "";
s.toUpperCase(); // okay
之类的基元也可以分配给花括号包围的类型,只要这些类型的成员匹配:
string
如果您确实需要表达仅接受“ true”的类型,即非原始对象,则可以使用object
:
const x: { length: number } = s; // okay
但是我(严重)离题了。
好的,希望能有所帮助;祝你好运!
答案 1 :(得分:1)
是的。在funcB
中,T必须扩展{},这几乎意味着除null and undefined以外的任何内容。 T可以是原始的。
答案 2 :(得分:0)
以下是指示通用参数,在以下情况下,用于指示函数可以接受的类型参数:
function funcA<T>(t: T) { }
您可以使用它来指示函数返回的类型,如下所示:
function funcA<T>() T {}
另一方面,T extends Something
表示该函数可以接受扩展Something
的任何参数。假设我们有一个接口Person
和一些实现Person
的接口,例如Teacher
,Student
,我们可以编写一个函数:
function funcA<T extends Person>(t: T)
我们只能使用扩展了T的参数调用funcA
。