Is there a way to receive second calculated type in overload method in typescript
type V1 = 'v1';
type V2 = 'v2';
type Versions = V1 | V2;
async analyze(test: 'v1', data: number): Promise<void>;
async analyze(test: 'v2', data: string): Promise<void>;
async analyze(test: Versions, data: string | number): Promise<void> {
switch (test) {
case 'v1':
return this.checkNumber(data); // data is number
case 'v2':
return this.checkString(data); // data is string
}
}
async checkString(data: string): Promise<void> {
console.log(data);
}
async checkNumber(data: number): Promise<void> {
console.log(data);
}
The only acceptable way I found for now is adding conditional typing to force type it inside switch:
type Data<Type> = Type extends V1 ? number : string;
async analyze(test: 'v1', data: number): Promise<void>;
async analyze(test: 'v2', data: string): Promise<void>;
async analyze(test: Versions, data: Data<typeof test>): Promise<void> {
switch (test) {
case 'v1':
return this.checkNumber(data as Data<typeof test>); // data is number
case 'v2':
return this.checkString(data as Data<typeof test>); // data is string
}
}
But are there any other ways?
CodePudding user response:
Because your method's return type doesn't depend on the type of the inputs (it's Promise<void>
no matter what), then instead of explicitly using overloads, you can use a discriminated union of tuple types as a rest parameter and destructure it into the test
and data
parameters. Uh, that's a lot of words; here, just look:
async analyze(
...[test, data]: [test: 'v1', data: number] | [test: 'v2', data: string]
): Promise<void> {
switch (test) {
case 'v1':
return this.checkNumber(data);
case 'v2':
return this.checkString(data);
}
}
The test
and data
on the left of the colon are destructured parameter names, while those on the right are tuple labels. The test
parameter will either be of type 'v1'
or of type 'v2
, and the data
parameter will either be of type number
or of type string
. But the compiler understands that 'v1'
for test
implies number
for data
, while 'v2'
for test
implies string
for data
, and so the rest of your implementation succeeds without error.
Functions taking unions of rest tuples look mostly like overloads from the caller's side, so things aren't that different for callers:
async calling() {
// IntelliSense shows 2 overloads:
// 1/2 analyze(test: "v1", data: number): Promise<void>
// 2/2 analyze(test: "v2", data: string): Promise<void>
this.analyze("v2", ""); // okay
this.analyze("v1", ""); // error
}
CodePudding user response:
You don't want to "mix" types but if you absolutely have to you can use datatype "any"
async someMethod(arg1: any) : Promise<void> {
...
}