[解決済み] 文字列ユニオンから文字列配列へ
質問
このような文字列ユニオン型があります。
type Suit = 'hearts' | 'diamonds' | 'spades' | 'clubs';
この文字列結合で使用できるすべての値を型安全な方法で取得したいのです。しかし、インターフェースは主に設計時の構成であるため、私にできる最善の方法はこれです。
export const ALL_SUITS = getAllStringUnionValues<Suit>({
hearts: 0,
diamonds: 0,
spades: 0,
clubs: 0
});
export function getAllStringUnionValues<TStringUnion extends string>(valuesAsKeys: { [K in TStringUnion]: 0 }): TStringUnion[] {
const result = Object.getOwnPropertyNames(valuesAsKeys);
return result as any;
}
この関数は、各キーが文字列結合の要素であるオブジェクトを常に渡し、すべての要素が含まれることを確認し、すべての要素の文字列配列を返します。そのため、文字列結合が変更された場合、この関数の呼び出しも更新されないとコンパイル時にエラーになります。
しかし
が問題です。
定数の型シグネチャが
ALL_SUITS
は
('hearts' | 'diamonds' | 'spades' | 'clubs')[]
. 言い換えると、TypeScriptはこれを、すべての値を一度だけ含む配列ではなく、これらの値のいずれか、あるいは複数を含み、重複している可能性がある配列と考える。
['hearts', 'diamonds', 'spades', 'clubs']
.
私が本当に欲しいのは、私の一般的な
getAllStringUnionValues
を返すように指定する方法です。
['hearts', 'diamonds', 'spades', 'clubs']
.
どうすれば実現できますか? 一般的に でありながら DRY を使うことができますか?
どのように解決するのですか?
TypeScript 3.4以上の場合の回答
TypeScriptでユニオンをタプルに変換することは、少なくともうまく動作する方法ではありません。 ユニオンは 順不同 であり、タプルは本質的に 順序付き であるため、何とかできたとしても、結果として得られるタプルは予期せぬ振る舞いをする可能性があります。 参照 この回答 をご覧ください。このメソッドは実際に論理和からタプルを生成しますが たくさん の注意書きがあります。 また マイクロソフト/TypeScript#13298 を参照してください。また、Union-to-tuple 変換に関する機能要求が却下されましたが、議論と、なぜこれがサポートされないかについての正式な回答があります。
しかし、使用例によっては、この問題を逆転させることができるかもしれません。 タプル 型を明示的に指定し ユニオン を導出します。 これは比較的簡単です。
TypeScript 3.4以降では、TypeScript 3.1以降では
const
アサーション
で、コンパイラにリテラルのタプルの型を推論するように指示します。
をリテラルタプルとして
としてではなく、例えば
string[]
. これは値に対して可能な限り狭い型を推論する傾向があり、例えばすべてを
readonly
. だから、こうすればいいんです。
const ALL_SUITS = ['hearts', 'diamonds', 'spades', 'clubs'] as const;
type SuitTuple = typeof ALL_SUITS; // readonly ['hearts', 'diamonds', 'spades', 'clubs']
type Suit = SuitTuple[number]; // "hearts" | "diamonds" | "spades" | "clubs"
TypeScript 3.0から3.3までの回答
TypeScript 3.0から、TypeScriptで
自動的にタプル型を推論する
. それがリリースされると
tuple()
という関数が必要になりますが、これは簡潔に次のように書くことができます。
export type Lit = string | number | boolean | undefined | null | void | {};
export const tuple = <T extends Lit[]>(...args: T) => args;
そして、このように使うことができます。
const ALL_SUITS = tuple('hearts', 'diamonds', 'spades', 'clubs');
type SuitTuple = typeof ALL_SUITS;
type Suit = SuitTuple[number]; // union type
3.0以前のTypeScriptに対する回答
この回答を投稿してから、ライブラリに関数を追加してくれるなら、タプル型を推論する方法を見つけました。 関数をチェックアウトして
tuple()
で
tuple.ts
.
これを使うと、以下のように書くことができ、繰り返しにならない。
const ALL_SUITS = tuple('hearts', 'diamonds', 'spades', 'clubs');
type SuitTuple = typeof ALL_SUITS;
type Suit = SuitTuple[number]; // union type
オリジナルの回答
あなたが望むものを得るための最も簡単な方法は、タプルの型を明示的に指定し、そこからユニオンを派生させることです。 はその方法を知らないのです。 . 例えば
type SuitTuple = ['hearts', 'diamonds', 'spades', 'clubs'];
const ALL_SUITS: SuitTuple = ['hearts', 'diamonds', 'spades', 'clubs']; // extra/missing would warn you
type Suit = SuitTuple[number]; // union type
リテラルを二度書き出していることに注意してください。
SuitTuple
で型として、そして
ALL_SUITS
TypeScriptは現在のところ、このような繰り返しを避けるための素晴らしい方法がないことに気づくだろう。
タプルを推論する
と指示することができず
決して
はタプル型から実行時配列を生成します。
ここでの利点は、実行時にダミーオブジェクトのキー列挙を必要としないことです。 もちろん、まだ必要であれば、スートをキーにした型を構築することもできます。
const symbols: {[K in Suit]: string} = {
hearts: '♥',
diamonds: '♦',
spades: '♠',
clubs: '♣'
}
お役に立てれば幸いです。
関連
-
[解決済み] TypeScriptで文字列を数値に変換する方法とは?
-
[解決済み] TypeScriptで Object.keys return string[].
-
[解決済み] TypeScriptの予約語 "type "とは何ですか?
-
[解決済み] describe'という名前が見つかりません。テストランナー用の型定義をインストールする必要がありますか?
-
[解決済み] ts ES5/ES3の非同期関数やメソッドには、「Promise」コンストラクタが必要です。
-
[解決済み] Typescriptでインターフェースやクラスを使用する場合 [重複].
-
[解決済み] TypeScriptの配列を文字列リテラルに変換するタイプ
-
[解決済み] Angular 2でアプリ起動時にサービスを実行する方法
-
[解決済み] Visual Studio Code - インポート引用符の設定を調整する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] TypeScriptで Object.keys return string[].
-
[解決済み] TypeScriptの予約語 "type "とは何ですか?
-
[解決済み] describe'という名前が見つかりません。テストランナー用の型定義をインストールする必要がありますか?
-
[解決済み] ts ES5/ES3の非同期関数やメソッドには、「Promise」コンストラクタが必要です。
-
[解決済み] Typescriptでインターフェースやクラスを使用する場合 [重複].
-
[解決済み] Angular 2でアプリ起動時にサービスを実行する方法
-
[解決済み] Visual Studio Code - インポート引用符の設定を調整する