TypeScript泛型函数如何禁止对象出现非枚举的多余键
解决方案
核心问题出在你原来的Smth类型使用了[key: string]索引签名,TypeScript默认会允许索引签名覆盖范围内的任意多余属性,不会触发多余属性校验,所以才会出现非法字段不报错的问题。
解决思路是去掉泛型约束里的索引签名,改用额外的校验逻辑对每个传入的属性做逐字段校验,多余的键会被标记为never类型,触发精准的字段级报错,同时完全保留原有返回类型推导能力:
const enum SomeEnum { a = "a", b = "b", } // 定义允许出现的键集合 type AllowedKeys = keyof typeof SomeEnum | 'args' // 原有属性的合法类型约束 type LegalEntryType = { args?: { [key: string]: () => string } } & Record<SomeEnum, string> // 校验逻辑:合法键保留原类型,非法键值类型设为never触发报错 type ValidateEntry<T> = T extends LegalEntryType ? { [K in keyof T]: K extends AllowedKeys ? T[K] : never } : LegalEntryType // 保留原有返回类型逻辑不变 type FnReturn<S> = { [key in keyof S]: { [key2 in SomeEnum]: S[key] extends { args: any } ? () => string : string } } function f<S extends Record<string, object>>(obj: S & {[K in keyof S]: ValidateEntry<S[K]>}): FnReturn<S> { return null! } const t = f({ prop1: { a: "abc", b: "def", }, prop2: { args: {}, a: "zzz", b: "xxx", }, prop3: { a: "ok", b: "fine", oooops: "???", // 此处直接报错:不能将类型“string”分配给类型“never”,错误精准定位到当前非法字段 } })
效果说明
- 非法多余字段会直接触发精准报错,错误标记在多余字段本身,不会影响其他合法字段的校验
- 原有返回值推导完全和之前一致,变量
t的类型和你给出的预期完全相同 - 泛型逻辑完整保留,原有功能不受任何影响
- 如果缺少必填的
a/b字段、或者args类型不符合要求,也会正常触发对应报错
内容的提问来源于stack exchange,提问作者Qwertiy
相关产品推荐
相关产品推荐

