• ..

npm

    Conditional Type

    基本

    このような形です。

    /**
     * P(arent), C(hild)
     */
    type T<U, V> = C extends P ? U : V;

    これはCPの拡張形式ならU型に、違うならV型になるという意味になります。

    同じプロパティを持ってればtrueな感じ、なので継承はtrue

    class P {}
    class C {}
    // type T = U
    
    class P {
      foo: any;
    }
    class C extends P {}
    // type T = U
    
    class P {
      foo: any;
    }
    class C {}
    // type T = V

    Generics で複数の型を提供する

    if-else-if-elseのように 2 つ以上の条件も設定できます。

    これは属すからtrueな感じ

    enum StatusCode {
      BadRequest = 400,
      NotFound = 404,
      InternalServerError = 500
    }
    /**
     * @alias
     */
    type Code = StatusCode;
    
    interface BadRequestResponse {
      code: Code.BadRequest;
      fields: any[];
    }
    
    interface NotFoundResponse {
      code: Code.NotFound;
      errors: any[];
    }
    
    interface InternalServerErrorResponse {
      code: Code.InternalServerError;
      message: any;
    }
    
    type Response<C extends Code> = Code.BadRequest extends C
      ? BadRequestResponse
      : Code.NotFound extends C
      ? NotFoundResponse
      : InternalServerErrorResponse;
    
    type A = Response<Code.NotFound>;
    // type A = NotFoundResponse
    type B = Response<Code.InternalServerError>;
    // type B = InternalServerErrorResponse

    infer で一部分の型を取得する

    以下は関数の戻り値を取得できます。inferはパターンマッチみたく、その場の型を条件結果の部分で使うことができます。

    type ReturnType<T extends Function> = T extends (...args: any[]) => infer F
      ? F
      : never;
    type A = ReturnType<() => number>;
    // type A = number;

    実はReturnTypeは最初から定義されてるので実装はいりません。

    type A = ReturnType<Fn>;

    例えば、第 2 引数の型が取りたい場合は、引数の型指定部分でinferを使います。

    // tslint:disable:no-unused
    type SecondArg<T extends Function> = T extends (
      a1: any,
      //  F が [tslint] TypeParameter 'F' is unused. [no-unused]
      // になってしまうので tslint:disable してます
      a2: infer F,
      ...args: any[]
    ) => any
      ? F
      : never;
    // tslint:enable:no-unused
    type A = SecondArg<(_a: number, _b: string, _c: boolean) => {}>;
    // type A = string