如何在TypeScript中按对象键调用不同参数的函数并规避类型错误?
问题分析与解决方案
原代码的核心问题在于:你用Record<string, (arg: base | base2) => string>强制统一了所有格式化函数的参数类型,但func1仅接受base类型、func2仅接受base2类型,二者并不兼容base | base2的联合类型(比如func1无法处理base2类型的参数),因此会触发类型错误。
下面提供两种优雅的解决方案,既保留抽象调用的能力,又保证类型安全:
方案1:明确绑定键与函数类型
直接定义一个精准的Formatter类型,让每个键对应正确的函数签名:
interface base { name: string; } interface base2 { title: string; } const func1 = (arg: base) => { return arg.name; } const func2 = (arg: base2) => { return arg.title; } // 明确每个键对应的函数类型 type Formatter = { format: typeof func1; format2: typeof func2; }; const formatter: Formatter = { format: func1, format2: func2 } // 类型安全的调用,无错误 formatter["format"]({ name: "test" }); formatter["format2"]({ title: "demo" });
方案2:映射类型实现可扩展的抽象
如果需要后续扩展更多格式化函数,可以用映射类型将键与参数类型绑定,实现更灵活的抽象:
interface base { name: string; } interface base2 { title: string; } // 定义键到参数类型的映射关系 type FormatterParamMap = { format: base; format2: base2; // 后续新增格式化规则时,直接在这里添加键和对应的参数类型即可 }; // 根据映射关系自动生成Formatter类型 type Formatter = { [Key in keyof FormatterParamMap]: (arg: FormatterParamMap[Key]) => string; }; // 实现格式化函数 const func1 = (arg: base) => arg.name; const func2 = (arg: base2) => arg.title; const formatter: Formatter = { format: func1, format2: func2 }; // 类型安全的调用 formatter.format({ name: "test" }); formatter.format2({ title: "demo" }); // 动态调用时也能保证类型安全 function callFormatter<Key extends keyof Formatter>(key: Key, arg: FormatterParamMap[Key]) { return formatter[key](arg); } callFormatter("format", { name: "dynamic test" });
这两种方案都能让TypeScript准确推断每个函数的参数类型,避免类型错误的同时,保留了通过键名调用函数的抽象能力。
内容的提问来源于stack exchange,提问作者Ali Osman
相关产品推荐
相关产品推荐

