ReturnType
给出的类型似乎取决于重载签名的写入顺序
function applyChanges1(input: string): number
function applyChanges1(input: number): string
function applyChanges1(input: number | string): number | string {
return typeof input === "number" ? input.toString() : input.length
}
function applyChanges2(input: number): string
function applyChanges2(input: string): number
function applyChanges2(input: number | string): number | string {
return typeof input === "number" ? input.toString() : input.length
}
type Ret1 = ReturnType<typeof applyChanges1> // string
type Ret2 = ReturnType<typeof applyChanges2> // number
似乎采用了最后一个重载签名的返回类型,这似乎很随意。我期望Ret1
和Ret2
都为string | number
。有这种行为的原因吗?
答案 0 :(得分:5)
正如Matt McCutchen指出的那样,这是ReturnType
的局限性,在一般条件类型和多个重载签名中都是这样。
但是我们可以构造一个类型,该类型将返回所有重载的返回类型,最多返回任意数量的重载:
function applyChanges1(input: string): number
function applyChanges1(input: number): string
function applyChanges1(input: number | string): number | string {
return typeof input === "number" ? input.toString() : input.length
}
function applyChanges2(input: number): string
function applyChanges2(input: string): number
function applyChanges2(input: number | string): number | string {
return typeof input === "number" ? input.toString() : input.length
}
type OverloadedReturnType<T> =
T extends { (...args: any[]) : infer R; (...args: any[]) : infer R; (...args: any[]) : infer R ; (...args: any[]) : infer R } ? R :
T extends { (...args: any[]) : infer R; (...args: any[]) : infer R; (...args: any[]) : infer R } ? R :
T extends { (...args: any[]) : infer R; (...args: any[]) : infer R } ? R :
T extends (...args: any[]) => infer R ? R : any
type RetO1 = OverloadedReturnType<typeof applyChanges1> // string | number
type RetO2 = OverloadedReturnType<typeof applyChanges2> // number | string
以上版本最多可用于4个重载签名(无论它们可能是什么),但可以轻松地(如果不是很漂亮的话)扩展到更多。
我们甚至可以通过相同的方式获得可能的参数类型的并集:
type OverloadedArguments<T> =
T extends { (...args: infer A1) : any; (...args: infer A2) : any; (...args: infer A3) : any ; (...args: infer A4) : any } ? A1|A2|A3|A4 :
T extends { (...args: infer A1) : any; (...args: infer A2) : any; (...args: infer A3) : any } ? A1|A2|A3 :
T extends { (...args: infer A1) : any; (...args: infer A2) : any } ? A1|A2 :
T extends (...args: infer A) => any ? A : any
type RetO1 = OverloadedArguments<typeof applyChanges1> // [string] & [number]
type RetO2 = OverloadedArguments<typeof applyChanges2> // [number] & [string]
答案 1 :(得分:1)
这是known limitation。 TypeScript团队的建议是包括“最一般”的过载签名作为您的最后一个过载签名,例如:
function applyChanges1(input: string): number
function applyChanges1(input: number): string
function applyChanges1(input: number | string): number | string
function applyChanges1(input: number | string): number | string {
return typeof input === "number" ? input.toString() : input.length
}
Titian Cernicova-Dragomir在他的答案中有一个更好的替代解决方案。
答案 2 :(得分:1)
我遇到了类似的问题-我需要根据我的自变量来选择 exact 的const { MyClass4TS } = require('MyClass4TS');
const instance = new MyClass4TS();
。
例如:
ReturnType
因此,我根据上面@Titian的漂亮答案并使用function applyChanges1(input: string): number
function applyChanges1(input: number): string
function applyChanges1(input: boolean): object
function applyChanges1(input: number | string | boolean): number | string | object {
return typeof input === "number" ? input.toString()
: typeof input === "boolean" ? { input }
: input.length;
}
// Needed:
type Ret11 = ReturnTypeWithArgs<typeof applyChanges1, [string]> // number
type Ret12 = ReturnTypeWithArgs<typeof applyChanges1, [number]> // string
type Ret13 = ReturnTypeWithArgs<typeof applyChanges1, [boolean]> // object
type Ret14 = ReturnTypeWithArgs<typeof applyChanges1, [number | string]> // number | string
type Ret15 = ReturnTypeWithArgs<typeof applyChanges1, [number | boolean]> // string | object
type Ret16 = ReturnTypeWithArgs<typeof applyChanges1, [number | string | boolean]> // number | string | object
创建了以下ReturnTypeWithArgs
实用程序。
Extract
它就像一种魅力!
PS。在我的真实情况下,我有7个超载,所以祝我好运! ; D