在联合类型上应用 ReturnType

Apply ReturnType on union type

TypeScript 不能在联合类型上使用 ReturnType 吗?

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]> 给出以下错误:

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)

conditional type does not get its types narrowed. So in 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 的错误分支是 TypeScript 中的一个已知问题,但它没有被合并。我不清楚这个问题是否或何时会得到解决。

在那之前,在必要时缩小自己的范围很容易(如果很烦人的话):

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

或者可能

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