

valueの型を指定したオブジェクトがあります。

[code]

    export type SingleTextEditorParamList = {
      title: string;
      value: string | undefined;
      onSubmit: (text: string) => Promise<void>;
      note?: React.ReactNode;
    };
    
    const SingleTextEditorParams: Record<string, SingleTextEditorParamList> = {
      a: {...省略},
      b: {...省略},
      c: {...省略},
      d: {...省略} 
    };
    
[/code]

SingleTextEditorParamsから`a|b|c|d`の型を作ることは可能でしょうか？

[code]

    type SingleTextEditorParamKeys = keyof typeof SingleTextEditorParams;
    
[/code]

これだと`string`になってしまいます。

[code]

    const SingleTextEditorParams: {[key: string]: SingleTextEditorParamList} = {省略}
    
[/code]

これも試しましたが`string | number`になりました。

[code]

    type SingleTextEditorParamKeys = a|b|c|d;
    
    const SingleTextEditorParams: {[key in SingleTextEditorParamKeys]: SingleTextEditorParamList} = {省略}
    
[/code]

ってすると、キーが増えた時、二箇所にキーを追加するのが冗長なので嫌だなと思いまして。もし方法があったら教えてください。


CC BY-SA 4.0
2022-08-04T01:31:17.090
90373
2022-08-12T06:55:58.813
15048
question
typescript
valueの型を指定したオブジェクトからkeyof typeofでkeyのユニオン型を作る


型アノテーションをつけない `SingleTextEditorParams` (仮に `UntypedSingleTextEditorParams`
とします) を先に作り、  
`SingleTextEditorParamKeys` は `keyof typeof UntypedSingleTextEditorParams`
とするのはいかがですか。

[code]

    const UntypedSingleTextEditorParams = {
        a: ...,
        b: ...,
        c: ...,
        d: ...,
    };
    
    type SingleTextEditorParamKeys =
        keyof typeof UntypedSingleTextEditorParams;
    
    const SingleTextEditorParams
        : Record<SingleTextEditorParamKeys, SingleTextEditorParamList>
        = UntypedSingleTextEditorParams;
    
[/code]


CC BY-SA 4.0
2022-08-05T16:02:15.577
90390
2022-08-05T16:15:52.680
2022-08-05T16:15:52.680
9464
9464
90373
answer


まず：`Record<string, SingleTextEditorParamList>`は`{[key: string]:
SingleTextEditorParamList}`とほとんど一緒です。Recordの意味については[公式ドキュメント](https://www.typescriptlang.org/docs/handbook/utility-
types.html#recordkeys-type)が詳しいのでそちらをご覧ください。

* * *

問題を解決するためには単に`SingleTextEditorParams`の型注釈を外し、`type SingleTextEditorParamKeys =
keyof typeof
SingleTextEditorParams`を追加すると良いです。現在の`SingleTextEditorParams`は`Record<string,
SingleTextEditorParamList>`となっているので、`keyof typeof
SingleTextEditorParams`の結果は`string`となります。


CC BY-SA 4.0
2022-08-06T12:11:46.050
90406
2022-08-06T12:11:46.050
44531
90373
answer


直接的な方法は無いようです。

### キーの型だけ推論する構文は無い

質問の動作を実現するには、下記のように、プロパティの値の型は明示（`Foo`）しつつ、キーの型は代入するオブジェクトリテラルから推論する、という構文が必要です。

[code]

    const fooRec: Record<ここを推論, Foo> = {
        a: { prop: "string" },
        b: { prop: "string" },
        c: { prop: "string" },
    }
    
[/code]

しかし、このような構文はありません。issue にて要望はいくつか出されています。

  * <https://github.com/microsoft/TypeScript/issues/26242>
  * <https://github.com/microsoft/TypeScript/issues/45139>

### ジェネリック関数の呼び出しを利用する方法

代替案として、既存の回答にあるように、型を記述せずにすべて推論させる方法があります。この場合、型チェックは変数の使用時に行われるので、エラーが出る箇所などが少し理想と異なります。

できるだけオブジェクトリテラルを書く場所で型チェックを行ないたい場合は、ジェネリック関数の呼び出しを利用する方法があります。ジェネリック関数の呼び出しでは、引数の型チェックを行いつつ、ジェネリック部は推論させることができるので、都合がよいです。

例:

[code]

    type Foo = {
        prop: string
    }
    
    // Record のキーの型を T とし、呼び出し箇所で推論する
    function initFooRec<T extends string>(x: Record<T, Foo>): Record<T, Foo> {
        return x
    }
    
    // fooRec は Record<"a" | "b" | "c", Foo>
    const fooRec = initFooRec({
        a: { prop: "string" },
        b: { prop: "string" },
        c: { prop: "string" },
    
        // 下のように Foo 型ではない値を入れると、エラーとして検出できる
        // d: { prop: "string", x: 123 },
    })
    
    // FooRecKeys は  "a" | "b" | "c"
    type FooRecKeys = keyof typeof fooRec
    
[/code]

キーの型を推論するのに使う `initFooRec` は引数をそのまま返すだけの恒等関数としています。実行時の処理があるならば加えてもよいでしょう。


CC BY-SA 4.0
2022-08-12T06:55:58.813
90523
2022-08-12T06:55:58.813
3054
90373
answer