如何基于首个参数为TypeScript函数实现第二个参数的类型校验?
解决TypeScript函数参数的精确属性约束问题
你的需求很明确:要让config参数的属性只能来自values数组中对象的属性,且不能包含额外属性,同时不需要提前定义接口,还要支持config在别处定义的场景。
问题根源
TypeScript只有对直接传入的对象字面量会做「超额属性检查」,如果config是一个提前定义的变量,TypeScript会默认推断它的类型为宽松的对象类型(允许额外属性),这就是为什么你的原始代码里wrong属性不会报错。
核心解决方案:精确类型约束
我们可以通过定义一个精确的Config类型,限制它只能包含keyof T中的属性,任何额外属性都会触发类型错误。具体实现是给Config<T>添加一个额外的约束:所有不在keyof T中的属性必须为never类型。
完整代码示例
// 定义CustomType保持不变 type CustomType<T> = { [K in keyof T]: number }; // 定义精确的Config类型:仅允许keyof T中的属性,额外属性会被never约束 type Config<T> = Partial<{ [K in keyof T]: { highPriority: boolean; callback: (values: any[]) => number[]; }; }> & Record<Exclude<string | number | symbol, keyof T>, never>; // 函数定义保持泛型,无需修改 const customFunction = <T>(values: T[], config: Config<T>): Array<CustomType<T>> => { // 你的业务逻辑... return []; }; // 示例values数组 const values = [ { foo: 'foo', bar: 'bar' }, { foo: 'foo', bar: 'bar' } ]; // 在其他位置定义config时,显式指定类型为Config<typeof values[0]> const config: Config<typeof values[0]> = { foo: { highPriority: true, callback: () => [] }, // 下面这行会触发TypeScript错误:类型"{ highPriority: true; callback: () => never[]; }"不能赋值给类型"never" wrong: { highPriority: true, callback: () => [] } }; // 调用函数,此时config的错误会被提前检测到 const result = customFunction(values, config);
为什么这个方案有效?
Partial<{[K in keyof T]: ...}>确保config可以包含T的任意子集属性(可选)。Record<Exclude<string | number | symbol, keyof T>, never>限制了所有不在keyof T中的属性必须为never类型,而任何实际的属性值都无法匹配never,因此额外属性会直接报错。- 当
config在别处定义时,只需要显式指定它的类型为Config<typeof values[0]>,就能关联values的类型,实现自动校验。
另一种方案:泛型辅助函数
如果你不想每次都显式指定config的类型,可以写一个辅助函数来创建config,自动关联values的类型:
function createConfig<T>(values: T[]): (config: Config<T>) => Config<T> { return (config) => config; } // 使用辅助函数创建config const config = createConfig(values)({ foo: { highPriority: true, callback: () => [] }, // 这里同样会报错 wrong: { highPriority: true, callback: () => [] } });
这个辅助函数利用泛型推断,自动把config的类型约束为Config<T>,无需手动指定类型,更简洁。
内容的提问来源于stack exchange,提问作者crazko
相关产品推荐
相关产品推荐

