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'
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;
}
_変数名として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]
もできません。 また、私の特定の
ユースケース、 list
をstatic
設定できません
@ 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]
もできません。 また、私の特定の
ユースケース、list
をstatic
設定できません
@vegerot const
をclass
のスコープで直接使用することはできないため、構文が正しくありません。
@ 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]
もできません。 また、私の特定の
ユースケース、list
をstatic
設定できません@vegerot
const
をclass
のスコープで直接使用することはできないため、構文が正しくありません。
@ 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]
もできません。 また、私の特定の
ユースケース、list
をstatic
設定できません@vegerot
const
をclass
のスコープで直接使用することはできないため、構文が正しくありません。@ 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
お役に立てて嬉しいです!
最も参考になるコメント
[email protected]以降。 このように解決する