≪ Today I learned.
RSS購読
    公開日
    タグ
    TypeScript
    著者
    ダーシノ

    TypeScriptの型で使われる-?や-readonlyの意味

    TypeScriptの型パズルを見ていると-?-readonlyという記号を見かける。非常にググラビリティが悪い。

    この-という記号は、続く?readonlyを除外するという役割がある。

    公式ドキュメントではreadonly mapped type modifiers and readonly arrays | TypeScript 3.4で軽く触れられている程度。

    Required<T>を使う場合

    ?というオプショナルな状態を除外するためにRequired<T>を使うと以下のようになる。

    type Item = {
        optional?: string
        require: string,
        children: {
            optional?: string
            require: string 
        }
    }
    
    // children は optional のまま
    type RequiredItem = Required<Item>

    ネストされたオブジェクトに対してはRequired<T>が適用されない。

    DeepRequired<T>を使う場合

    ネストされたオブジェクトに再帰的にRequired<T>を適用することもできる。ただし、以下のようにchildrenがRequired<{...}>という形になってしまう。

    type DeepRequired<T> = T extends object
      ? Required<{ [K in keyof T]: DeepRequired<T[K]> }>
      : T
    
    type RequiredAll = DeepRequired<Item>
    // {
    //     optional: string;
    //     require: string;
    //     children: Required<{
    //         optional?: string | undefined;
    //         require: string;
    //     }>;
    // }

    -?を使う場合

    -?を使って?(オプショナル)を除外すると、Required<T>が現れないプレーンなオブジェクトの型になる。

    type DeepRequired<T> = T extends object
      ? { [K in keyof T]-?: DeepRequired<T[K]> }
      : T
    type RequiredAll = DeepRequired<Item>
    // {
    //     optional: string;
    //     require: string;
    //     children: {
    //         optional: string;
    //         require: string;
    //     };
    // }

    -readonlyの場合

    -readonlyも同様にreadonlyを除外するために使える。

    type Item = {
      readonly val: string
    }
    
    type Editable<T> = T extends object
      ? { -readonly [K in keyof T]: Editable<T[K]> }
      : T
    
    type EditableAll = Editable<Item>
    // {
    //   val: string
    // }