泛型约束 (T extends ...) 限制了泛型参数可以是什么类型,这样您可以安全地在其上使用某些属性或方法。没有约束的话,泛型可以是任何东西,所以您不能假设它有任何成员。
ts
longestBad<T>(: T, : T) {
a. > b. ? a : b;
}
longest<T { : }>(: T, : T): T {
a. > b. ? a : b;
}
(, );
([, ], []);
(, );
泛型约束 (T extends ...) 限制了泛型参数可以是什么类型,这样您可以安全地在其上使用某些属性或方法。没有约束的话,泛型可以是任何东西,所以您不能假设它有任何成员。
longestBad<T>(: T, : T) {
a. > b. ? a : b;
}
longest<T { : }>(: T, : T): T {
a. > b. ? a : b;
}
(, );
([, ], []);
(, );
约束是一个承诺:"T 总是至少具有这种形状",这让编译器在保持 T 精确的同时允许 .length(返回类型是实际的数组/字符串类型,而不是约束)。
function pluck<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
K extends keyof T 保证 key 是 obj 的真实属性——而 T[K] 返回其确切类型。
interface Box<T = string> { value: T; } // T defaults to string if not specified
约束是灵活性和安全性之间的平衡:它们让泛型代码依赖于最小形状(有 .length、有键 K、扩展某个基类),同时保留调用者的特定类型。
它们对于实用函数、类型安全的对象访问以及任何需要对其类型参数执行操作的泛型都是必不可少的。