如何配置TypeScript限制字面量表达式仅接受可用属性?
解决TypeScript中多余属性赋值的编译时检查问题
这个问题的核心在于TypeScript的结构类型系统默认允许多余属性赋值——当赋值源是变量而非直接对象字面量时,TS只会校验目标类型要求的属性是否存在,不会限制额外属性。要解决这个问题,我们可以从编译时检查和运行时约束两个角度入手,下面是几种可行的方案:
方案1:泛型工具函数(编译时+运行时约束)
写一个通用的pick函数,只提取目标类型指定的属性,既在编译时阻止多余属性的类型赋值,又能在运行时移除多余属性。这种方案不管有没有实例对象都适用,只有类型定义时手动传入属性键即可:
// 泛型pick函数:从对象中提取指定键的属性 const pick = <T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> => { const result = {} as Pick<T, K>; keys.forEach(key => { result[key] = obj[key]; }); return result; }; // 示例场景:有实例对象的情况 const foo = { "a" :1, "b" :2, "c" :3 } const foo2 = { "a":1, "c":2 } type Foo2Type = typeof foo2; // 从foo中提取foo2类型的所有属性 const foo3: Foo2Type = pick(foo, ...(Object.keys(foo2) as Array<keyof Foo2Type>)); // foo3仅包含a和c属性,编译时无多余属性报错,运行时也不会有b属性 // 仅定义类型无实例的场景 type TargetType = {a: number; c: number}; const foo4: TargetType = pick(foo, 'a', 'c');
方案2:编译时类型校验(仅检查不修改运行时)
如果只需要在编译时阻止多余属性赋值,不需要运行时移除属性,可以通过自定义交叉类型来实现。这个方案利用Exclude工具类型检测是否存在多余属性:
// 自定义类型:如果U包含T没有的属性,则返回never(触发类型错误) type ExcessPropertiesError<T, U> = Exclude<keyof U, keyof T> extends never ? U : never; const foo = { "a" :1, "b" :2, "c" :3 } type Foo2Type = {a: number; c: number}; // 仅类型定义,无实例 // 交叉类型会在foo包含Foo2Type以外的属性时报错 const foo3: Foo2Type & ExcessPropertiesError<Foo2Type, typeof foo> = {...foo}; // 此时TS会抛出类型错误:类型"{ a: number; b: number; c: number; }"不能赋值给类型"Foo2Type & never"
为什么原代码不报错?
补充说明一下:当你直接用对象字面量赋值给Foo2Type时,TS会触发多余属性检查(比如const foo3: Foo2Type = {a:1, c:2, b:3}会报错),但当赋值源是变量(比如...foo)时,TS的结构类型系统会认为变量可能是动态生成的,因此默认允许多余属性存在。上面的方案就是专门针对这种场景做的约束。
内容的提问来源于stack exchange,提问作者minjae kim
相关产品推荐
相关产品推荐

