使用含构造签名与普通签名的接口定义函数时TypeScript报错
问题原因
你定义的CallOrConstruct类型要求函数同时满足两个独立的签名:
- 普通调用时,输入
number必须返回string - 构造调用时,输入
string必须返回Date
但你写的fn函数类型被推断为(input: string | number) => string | Date,TypeScript无法自动将这个联合输入输出的函数和分场景签名的CallOrConstruct匹配——因为类型系统认为,当你用number调用fn时,它可能返回Date(虽然运行时不会,但类型层面没约束死),所以不符合CallOrConstruct的第一个签名要求。
解决方案1:用函数重载实现符合签名的函数
直接给fn定义重载签名,让TypeScript明确不同输入对应的输出,这是最符合TypeScript类型系统设计的方式:
type CallOrConstruct = { (n: number): string; new (s: string): Date; }; // 定义重载签名 function fn(n: number): string; function fn(s: string): Date; // 构造函数重载 function new fn(s: string): Date; // 函数实现体 function fn(input: number | string): string | Date { if (typeof input === "number") { return input.toString(); } return new Date(input); } function callableFn( fn: CallOrConstruct, input: number | string ): string | Date { if (typeof input === "number") { return fn(input); } return new fn(input); // 无需额外断言 } callableFn(fn, 124); callableFn(fn, "2024-04-06");
解决方案2:对fn进行类型断言
如果不想修改fn的实现结构,可以直接断言fn符合CallOrConstruct类型,前提是你确保运行时逻辑完全匹配签名要求:
type CallOrConstruct = { (n: number): string; new (s: string): Date; }; function fn(input: number | string): string | Date { if (typeof input === "number") { return input.toString(); } return new Date(input); } function callableFn( fn: CallOrConstruct, input: number | string ): string | Date { if (typeof input === "number") { return fn(input); } return new fn(input); } // 调用时断言fn的类型 callableFn(fn as CallOrConstruct, 124); callableFn(fn as CallOrConstruct, "2024-04-06");
解决方案3:用泛型关联输入输出类型
给callableFn添加泛型约束,让TypeScript自动推断不同输入对应的返回类型,同时保持类型严谨性:
type CallOrConstruct = { (n: number): string; new (s: string): Date; }; function fn(input: number | string): string | Date { if (typeof input === "number") { return input.toString(); } return new Date(input); } // 泛型关联输入类型与返回类型 function callableFn<T extends number | string>( fn: CallOrConstruct, input: T ): T extends number ? string : Date { if (typeof input === "number") { return fn(input) as T extends number ? string : Date; } return new fn(input) as T extends number ? string : Date; } callableFn(fn as CallOrConstruct, 124); // 返回类型自动推断为string callableFn(fn as CallOrConstruct, "2024-04-06"); // 返回类型自动推断为Date
内容的提问来源于stack exchange,提问作者vivek bhansali
相关产品推荐
相关产品推荐

