简体   繁体   中英

Apply ReturnType on union type

Is TypeScript incapable of using ReturnType on union types?

type NumberParser = (input: string) => number | DiplomacyError;
type StringParser = (input: string) => string | DiplomacyError;
type Parser = NumberParser | StringParser;

export interface Schema {
  [key: string]: Parser | Schema;
}

export type RawType<T extends Schema> = {
  [Property in keyof T]: T[Property] extends Schema
    ? RawType<T[Property]>
    : ReturnType<T[Property]>; // T[Property] marked as error
};

<T[Property]> gives the following error:

Type 'T[Property]' does not satisfy the constraint '(...args: any) => any'.
  Type 'T[keyof T]' is not assignable to type '(...args: any) => any'.
    Type 'T[string] | T[number] | T[symbol]' is not assignable to type '(...args: any) => any'.
      Type 'T[string]' is not assignable to type '(...args: any) => any'.
        Type 'Parser | Schema' is not assignable to type '(...args: any) => any'.
          Type 'Schema' is not assignable to type '(...args: any) => any'.
            Type 'Schema' provides no match for the signature '(...args: any): any'.ts(2344)

It is a known issue in TypeScript that the false branch of a conditional type does not get its types narrowed. So in T extends U? F<T>: G<T> T extends U? F<T>: G<T> does not take G<T> and replace it with something like G<Exclude<T, U>> . As far as the compiler is concerned, the T in G<T> might still be assignable to U , even though it's obvious to us that it won't be. See microsoft/TypeScript#29188 . It looks like there was some work done to address this at microsoft/TypeScript#24821 , but it was not merged. It's not clear to me if or when this issue will be resolved.

Until then, it's easy enough (if annoying) to do such narrowing yourself when necessary:

export type RawType<T extends Schema> = {
    [K in keyof T]: T[K] extends Schema
    ? RawType<T[K]>
    : ReturnType<Exclude<T[K], Schema>>;
};

Or possibly

export type RawType<T extends Schema> = {
    [K in keyof T]: T[K] extends Schema
    ? RawType<T[K]>
    : ReturnType<Extract<T[K], Parser>>;
};

Playground link to code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM