下面的两个通用类型参数之间在功能上是否有任何区别?
function funcA<T>() { }
function funcB<T extends {}>() {}
我看到这两个术语都被使用过,但是它们的区别让我感到困惑?
function funcA<T>() { }
function funcB<T extends {}>() {}
我看到这两个术语都被使用过,但是它们的区别让我感到困惑?
unknown
的约束,而不是空对象类型 {}
, 并且关于 funcA()
和 funcB()
之间的差异的一些细节也发生了变化。我不想通过谈论 TS3.4 及以下版本的情况来使一篇长帖子变得更长。
extends XXX
显式地约束泛型类型参数,那么它将隐式地受到unknown
的限制,这是所有类型都可以赋值的“顶级类型”。因此,在实践中,这意味着funcA<T>()
中的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
如果你需要表示只接受"true"的类型,即非原始对象,你可以使用object
:
const y: object & { length: number } = s; // error
const z: object & { length: number } = { length: 10 }; // okay
好的,希望能有所帮助;祝你好运!
function funcA<T>(t: T) { }
您可以使用以下方式指示函数返回的类型:
function funcA<T>(t:T):T {}
T extends Something
表示该函数可以接受任何扩展 Something
的参数。假设我们有一个接口 Person
和一些其他实现了 Person
的接口,如 Teacher
、Student
,我们可以编写一个函数:function funcA<T extends Person>(t: T)
我们只能使用扩展T的参数调用funcA
。