TypeScript中为何用extends keyof约束泛型而非in keyof?
在TypeScript中声明带约束的泛型类型参数时,为何使用“extends keyof”而非“in keyof”?
在TypeScript官网的泛型章节中,extends在声明类型参数时有两种典型用法:
1. 基础泛型约束
通过extends让泛型参数继承某个接口,确保其拥有指定的属性或方法:
interface Lengthwise { length: number; } function loggingIdentity<Type extends Lengthwise>(arg: Type): Type { console.log(arg.length); return arg; }
2. 用其他类型参数约束当前参数
用extends keyof限定泛型参数必须是另一个类型的键:
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) { return obj[key]; } let x = { a: 1, b: 2, c: 3, d: 4 }; getProperty(x, "a"); // 合法 getProperty(x, "m"); // 报错:类型'"m"'不能赋值给类型'"a" | "b" | "c" | "d"'
第一种用法符合OOP继承逻辑很好理解,但第二种场景中,为什么用extends keyof而不用映射类型里的in keyof?比如映射类型的示例:
type Optional<T> = { [K in keyof T]?: T[K]; };
核心原因:两者的语法定位和作用完全不同
extends是类型约束语法:它的作用是限定泛型参数的取值范围,要求泛型参数必须是目标类型的子类型。在Key extends keyof Type中,keyof Type会生成一个由Type所有键组成的联合类型,extends则要求Key必须是这个联合类型的子集(可以是单个键,也可以是多个键组成的子联合类型),以此约束传入的key参数必须是obj的合法键。in是映射遍历语法:它只能用于对象类型的属性定义中,作用是遍历一个联合类型的所有成员,为每个成员生成对应的属性。比如[K in keyof T]会遍历T的所有键,把每个键K都转换成新对象的可选属性,这是用来构建新类型的语法,根本不能用于泛型参数的约束场景——TypeScript的语法规则不允许在泛型参数声明中使用in。
简单来说,extends keyof是用来“限制单个参数的合法类型”,而in keyof是用来“批量生成对象属性”,两者的应用场景没有交集,自然不能混用。
内容的提问来源于stack exchange,提问作者Hasanta
相关产品推荐
相关产品推荐

