Javascript 定义TypeScript中重载函数的工厂
假设使用我自己的函数包装JSON.stringify:Javascript 定义TypeScript中重载函数的工厂,javascript,typescript,Javascript,Typescript,假设使用我自己的函数包装JSON.stringify: declare function stringify( value: any, replacer?: (key: string, value: any) => any, space?: string | number ): string; declare function stringify( value: any, replacer?: (number | string)[] | null,
declare function stringify(
value: any,
replacer?: (key: string, value: any) => any,
space?: string | number
): string;
declare function stringify(
value: any,
replacer?: (number | string)[] | null,
space?: string | number
): string;
function myStringify(
data: object,
replacer: ((key: string, value: any) => any) | (number | string)[] | null,
space: string | number,
) {
return stringify(data, replacer, space); // TS error: type is compatible!
}
如何创建我自己的方法myStringify重用JSON.stringify
您可以通过检查错误详细信息。问题在于,由于
replacer
是来自所有stringify
重载的replacer
参数类型的并集,因此它实际上与任何重载都不兼容。选择重载类型时,脚本将尝试查找与参数最匹配的重载,因为您的replacer
既不兼容第一个重载(该重载需要函数,您的参数也可以是数组)也不兼容第二个重载(该重载需要数组,您的参数可以是函数)过载解决过程将失败
您可以自己添加这两个重载,也可以使用类型保护来调用同一个函数,或者只使用断言:
// assert to any
function myStringify(
data: object,
replacer: ((key: string, value: any) => any) | (number | string)[] | null,
space: string | number,
) {
return JSON.stringify(data, replacer as any, space)
}
// use a type gurad, but it seems overkill to do so.
function myStringify(
data: object,
replacer: ((key: string, value: any) => any) | (number | string)[] | null,
space: string | number,
) {
if(Array.isArray(replacer)) {
return JSON.stringify(data, replacer, space);
} else if(typeof replacer === "function") {
return JSON.stringify(data, replacer, space);
}
}
受@Titian Cernicova Dragomir答案的启发,我找到了一个通用解决方案供参考。试试myFun2的做法
declare function s(r: () => string): string;
declare function s(r: () => number): number;
const a = s(() => '123') // sring
const b = s(() => 123) // number
function myFun(r: (() => string) | (() => number)) {
type R = ReturnType<typeof r> extends string ? string : number
return s(r)// TS error: type is compatible!
}
const c = myFun(() => '123') // string, is decide by the order we declare the function 's'
const d = myFun(() => 123) // string, totally wrong
function myFun2(r: () => string): string;
function myFun2(r: () => number): number;
function myFun2(r: (() => string) | (() => number)): string | number {
type R = ReturnType<typeof r> extends string ? string : number
return s(r as any) as any as R
}
const e = myFun2(() => '123')
const f = myFun2(() => 123)
声明函数s(r:()=>string):string;
声明函数s(r:()=>number):number;
常数a=s(()=>'123')///sring
常数b=s(()=>123)//个数
函数myFun(r:(()=>字符串)|(()=>数字)){
类型R=返回类型扩展字符串?字符串:编号
返回s(r)//TS错误:类型兼容!
}
const c=myFun(()=>'123')//字符串,由我们声明函数的顺序决定
const d=myFun(()=>123)//字符串,完全错误
函数myFun2(r:()=>string):string;
函数myFun2(r:()=>number):number;
函数myFun2(r:(()=>string)|(()=>number)):string | number{
类型R=返回类型扩展字符串?字符串:编号
返回s(r为任意)为任意r
}
常数e=myFun2(()=>123')
常数f=myFun2(()=>123)
解决方案二似乎不是通用的,如果replacer有两个不同的函数签名,我们就不能这样处理它。解决方案一有一个潜在的问题,即如果这两个重载具有不同的返回类型,我们将丢失准确的返回类型。@zheeng解决方案1确实绕过了类型安全性,并且可能会中断。如果联合包含更多的函数,解决方案2可能会出现问题,但是您不能为特定的函数签名键入guard,幸运的是在这种情况下只有一个。