Typescript: 配列の値から型を作成する

作成日 2018年10月22日  ·  16コメント  ·  ソース: microsoft/TypeScript


TypeScriptバージョン: 3.0.3


検索用語:配列の値に基づいて入力します

配列内の文字列から型を作成するための現在または計画中の機能はありますか?

コード

const values = ['A', 'B']
type Foo = OneOf<values> // Is there a way of doing this?

const v1: Foo = 'A' // This should work
const v2: Foo = 'D' // This should give me an error since 'D' doesn't exist in values

keyof仕組みと同様:

const values = {
  A: 'A',
  B: 'B'
}
type Foo = keyof typeof values
const v1: Foo = 'A'
const v2: Foo = 'D' // Type '"D"' is not assignable to type '"A" | "B"'

関連する問題:https://github.com/Microsoft/TypeScript/issues/20965

遊び場へのリンクhttp://www.typescriptlang.org/play/#src= let%20vals1%20%3D%20%5B'A '%2C%20'B'%5D%0D%0Atype%20Foo1%20% 3D%20OneOf%3Cvals1%3E%20%2F%2F%20Is%20there%20a%20way%20of%20doing%20this%3F%0D%0A%0D%0Alet%20v1%3A%20Foo1%20%3D%20 ' A '%20%2F%2F%20This%20should%20work%0D%0Alet%20v2%3A%20Foo1%20%3D%20' D '%20%2F%2F%20This%20should%20give%20me%20an% 20error%20since%20'D '%20does n't%20exist%20in%20values%0D%0A%0D%0Alet%20vals2%20%3D%20%7B%0D%0A%20%20A%3A%20'A '%2C%0D%0A%20%20B%3A%20' B '%0D%0A%7D%0D%0Atype%20Foo2%20%3D%20keyof%20typeof%20vals2%0D%0Alet%20v3%3A%20Foo2 %20%3D%20'A '%0D%0Alet%20v4%3A%20Foo2%20%3D%20'D'%20%2F%2F%20Type%20 '%22D%22'%20is%20not%20assignable %20to%20type%20 '%22A%22%20%7C%20%22B%22'

Question

最も参考になるコメント

[email protected]以降。 このように解決する

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

全てのコメント16件

keyofは、コンパイル時に静的に認識されている情報を使用するためにのみ機能します。 TSの型は完全に消去可能であり、トランスパイルされたコードには存在しないため、配列の実行時の内容に基づいて型を作成することは不可能です。

これは可能です:

function stringLiterals<T extends string>(...args: T[]): T[] { return args; }
type ElementType<T extends ReadonlyArray<unknown>> = T extends ReadonlyArray<infer ElementType> ? ElementType : never;

const values = stringLiterals('A', 'B');
type Foo = ElementType<typeof values>;

const v1: Foo = 'A' // This should work
const v2: Foo = 'D' // This should give me an error since 'D' doesn't exist in values

ただし、これを行う方法は明確ではありません。 #27179が関連しています。

それでも、コンパイラによって静的に認識されている情報を使用しています。 その時点では、 ”A” | “B”と言うだけの利点が何であるかわかりません。

@fatcerberus情報の繰り返しを避けると便利です。 const values = ["A", "B"]; type Foo = "A" | "B";と書くだけで、誰かが一方を変更するのを忘れて、もう一方を変更するのは簡単です。 const values: Foo[] =["A", "B"];と書くこともできますが、それでもFooエントリを追加して、 valuesに入れるのを忘れる可能性があります。

今、私たちはこれについてどこにいますか?

@ andy-msが言ったように、手動で情報を繰り返さないようにすることは本当に便利でしょう。
そして@fatcerberusが言ったように、タイプは完全に消去可能です。 たとえば、アプリケーションの純粋でない部分(Webサービスやユーザーなど)から取得したデータをランタイムチェックする必要がある場合があります。

@ andy-msの回答に基づいて構築し、typescript 3.4で導入されたconstアサーションを使用すると、次のようなことが可能になります。

const values = ['A', 'B'] as const
type ElementType < T extends ReadonlyArray < unknown > > = T extends ReadonlyArray<
  infer ElementType
>
  ? ElementType
  : never

type Foo = ElementType<typeof values> // this is correctly inferred as literal "A" | "B"

この問題は「質問」としてマークされており、最近の活動は見られません。 ハウスキーピングの目的で自動的に閉鎖されました。 それでも応答を待っている場合は、通常、質問がstackoverflowに適しています。

[email protected]以降。 このように解決する

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

これの代わりに:

export const items = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof items[number];
}

あなたはこれを行うことができます:

export const items = [
  'room',
  'room_with_gifter',
  'user_send'
] as const;

export type Item = typeof items;

export interface Activity {
  id?: string;
  type: Item;
}

image

_変数名としてtypeを使用するのは本当に好きではありません。_

@ 7kms

[email protected]以降。 このように解決する

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

これをクラスに持っているとどうなりますか?

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

動作しません。 this.list[number]もできません。 また、私の特定の
ユースケース、 liststatic設定できません

@ 7kms

[email protected]以降。 このように解決する

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

これをクラスに持っているとどうなりますか?

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

動作しません。 this.list[number]もできません。 また、私の特定の
ユースケース、 liststatic設定できません

@vegerot constclassのスコープで直接使用することはできないため、構文が正しくありません。

@ 7kms

[email protected]以降。 このように解決する

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

これをクラスに持っているとどうなりますか?

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

動作しません。 this.list[number]もできません。 また、私の特定の
ユースケース、 liststatic設定できません

@vegerot constclassのスコープで直接使用することはできないため、構文が正しくありません。

@ 7kms私の悪い。 コピー&ペーストしすぎました。 私が言いたかったのは

class Class {
  private list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 private withType: typeof list[number];

// OR
  private withType2: typeof this.list[number];

}

などすべてが動作しません。
また、私の特定のユースケースでは、リストを静的に設定できません

@ 7kms

[email protected]以降。 このように解決する

export const type = <const>[
  'room',
  'room_with_gifter',
  'user_send'
];

export interface Activity {
  id?: string;
  type: typeof type[number];
}

これをクラスに持っているとどうなりますか?

class Class {
  const list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 const withType: typeof list[number];
}

動作しません。 this.list[number]もできません。 また、私の特定の
ユースケース、 liststatic設定できません

@vegerot constclassのスコープで直接使用することはできないため、構文が正しくありません。

@ 7kms私の悪い。 コピー&ペーストしすぎました。 私が言いたかったのは

class Class {
  private list = <const>[
   'room',
   'room_with_gifter',
   'user_send'
 ];

 private withType: typeof list[number];

// OR
  private withType2: typeof this.list[number];

}

などすべてが動作しません。
また、私の特定のユースケースでは、リストを静的に設定できません

class Class {
  private list = [
    "room",
    "room_with_gifter",
    "user_send"
  ] as const

  private withType: Class["list"][number]
}

@vegerotこれはどうですか?

@eyalchそれは素晴らしいです! ありがとうございました。 解決策にはtypeofか何かが含まれると思いました。 これがどのように機能するかについて簡単に説明しますか、それともこれが説明されているハンドブックにリンクしてください。

@eyalchそれは素晴らしいです! ありがとうございました。 解決策にはtypeofか何かが含まれると思いました。 これがどのように機能するかについて簡単に説明しますか、それともこれが説明されているハンドブックにリンクしてください。

@vegerot確かに、これは「インデックスタイプ」だと思います。 これはハンドブックにあります: https ://www.typescriptlang.org/docs/handbook/advanced-types.html#index -types

お役に立てて嬉しいです!

ElementTypeソリューションでも機能しない場合
配列の後のas const注意してください。 それは重要です

このページは役に立ちましたか?
0 / 5 - 0 評価