Home > Mobile >  Is there a way to receive second calculated type in overload method in typescript?
Is there a way to receive second calculated type in overload method in typescript?

Time:07-15

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
}

Playground link to code

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> {
...
}
  • Related