如何让TypeScript对象偏应用函数拒绝传入对象的额外键?
解决对象偏应用函数的额外键限制问题
要让偏应用函数(partial)像原函数一样限制传入对象的额外键,得分**类型层面(TypeScript)和运行时层面(JavaScript/TypeScript通用)**两种场景处理:
一、TypeScript 类型层面限制(编译时报错)
TypeScript 默认仅对对象字面量做额外属性检查,赋值给变量后会丢失该校验。我们可以通过泛型约束让 partial 函数的参数严格匹配原函数的参数类型,直接在编译阶段拦截额外键。
实现方式:
利用泛型约束排除额外键,确保 partialParams 只能包含原函数参数类型中定义的键:
interface MyParams { a: number; b: string; } function originalFunc(params: MyParams) { console.log(params.a, params.b); } // 带严格类型检查的 partial 函数 function partial<T, P extends Partial<T>>( func: (params: T) => void, partialParams: P & Record<Exclude<keyof P, keyof T>, never> ) { return (remainingParams: Partial<T>) => { func({ ...partialParams, ...remainingParams } as T); }; } // 非法调用:传入额外键会触发编译错误 const badPartial = partial(originalFunc, { a: 123, c: true }); // 报错提示:类型“{ a: number; c: boolean; }”中属性“c”的类型不能赋给“never”类型的索引签名 // 合法调用 const goodPartial = partial(originalFunc, { a: 123 }); goodPartial({ b: "hello" }); // 正常执行
原理:
Record<Exclude<keyof P, keyof T>, never> 会校验 P 中是否存在 T 以外的键,如果有,这些键的类型会被约束为 never,而传入的具体值(比如 true)无法匹配 never,从而触发编译错误。
二、运行时层面限制(JavaScript/TypeScript通用)
如果需要在运行时拦截额外键(比如纯JS环境,或需要处理动态传入的对象),可以在 partial 函数中手动校验参数键的合法性。
实现方式:
先给原函数绑定允许的参数键列表,然后在 partial 函数中检查传入对象的键是否符合要求:
// 原函数,自带参数键校验逻辑 function originalFunc(params) { const allowedKeys = ['a', 'b']; const extraKeys = Object.keys(params).filter(key => !allowedKeys.includes(key)); if (extraKeys.length) { throw new Error(`不允许的额外参数:${extraKeys.join(', ')}`); } console.log(params.a, params.b); } // 带运行时校验的 partial 函数 function partial(func, partialParams) { const allowedKeys = func.allowedKeys || []; // 校验偏应用参数的额外键 const partialExtraKeys = Object.keys(partialParams).filter(key => !allowedKeys.includes(key)); if (partialExtraKeys.length) { throw new Error(`偏应用参数包含额外键:${partialExtraKeys.join(', ')}`); } return (remainingParams) => { // 校验剩余参数的额外键 const remainingExtraKeys = Object.keys(remainingParams).filter(key => !allowedKeys.includes(key)); if (remainingExtraKeys.length) { throw new Error(`剩余参数包含额外键:${remainingExtraKeys.join(', ')}`); } func({ ...partialParams, ...remainingParams }); }; } // 给原函数绑定允许的键列表 originalFunc.allowedKeys = ['a', 'b']; // 非法调用:传入额外键触发运行时错误 const badPartial = partial(originalFunc, { a: 123, c: true }); // 抛出错误:偏应用参数包含额外键:c // 合法调用 const goodPartial = partial(originalFunc, { a: 123 }); goodPartial({ b: "hello" }); // 正常执行
扩展:
如果用 TypeScript,可以通过工具(如ts-json-schema-generator)从类型生成运行时 schema,避免类型与运行时键列表不一致的问题。
内容的提问来源于stack exchange,提问作者francescortiz
相关产品推荐
相关产品推荐

