Typescriptは、タプル/配列値から共用体型を導出します


99

私がリストを持っていると言う const list = ['a', 'b', 'c']

この値の共用体タイプから派生することは可能'a' | 'b' | 'c'ですか?

静的配列からの値のみを許可する型を定義し、実行時にこれらの値を列挙する必要があるため、これが必要なので、配列を使用します。

インデックス付きオブジェクトを使用して実装する方法の例:

const indexed = {a: null, b: null, c: null}
const list = Object.keys(index)
type NeededUnionType = keyof typeof indexed

インデックス付きの地図を使わずにそれができるのだろうか。


つまり、基本的に、その場で型を生成したいですか?
SwiftsNamesake 2017

タイプはコンパイル時にのみ存在するため、実行時に動的に作成することはできません。
jonrsharpe 2017

これは興味深い質問です。あなたのユースケースは何ですか?
unional 2017

回答:


211

2019年2月の更新

2019年3月にリリースされるべき活字体3.4、リテラルのタプルの型を推論するためにコンパイラに指示することが可能となりますリテラルのタプルとして、言って、代わりのように、string[]使用することによって、as const構文を。このタイプのアサーションにより、コンパイラーは、すべてを作成することを含め、値に対して可能な限り狭いタイプを推測しますreadonly。次のようになります。

const list = ['a', 'b', 'c'] as const; // TS3.4 syntax
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c';

これにより、あらゆる種類のヘルパー関数が不要になります。皆さん、頑張ってください!


2018年7月の更新

TypeScript 3.0以降、TypeScriptがタプルタイプ自動的に推測できるようになるようです。リリースされると、tuple()必要な関数は次のように簡潔に記述できます。

export type Lit = string | number | boolean | undefined | null | void | {};
export const tuple = <T extends Lit[]>(...args: T) => args;

そして、次のように使用できます。

const list = tuple('a','b','c');  // type is ['a','b','c']
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'

それが人々のために働くことを願っています!


2017年12月の更新

この回答を投稿してから、ライブラリに関数を追加する場合は、タプルタイプを推測する方法を見つけました。tuple.tsの関数tuple()を確認してください。これを使用すると、次のように書くことができ、繰り返す必要はありません。

const list = tuple('a','b','c');  // type is ['a','b','c']
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'

幸運を!


オリジナル2017年7月

1つの問題は、リテラル['a','b','c']が型として推測されるstring[]ため、型システムが特定の値を忘れてしまうことです。型システムに各値をリテラル文字列として記憶させることができます。

const list = ['a' as 'a','b' as 'b','c' as 'c']; // infers as ('a'|'b'|'c')[]

または、おそらくより良いのは、リストをタプルタイプとして解釈することです。

const list: ['a','b','c'] = ['a','b','c']; // tuple

これは煩わしい繰り返しですが、少なくとも実行時に無関係なオブジェクトを導入することはありません。

今、あなたはこのようにあなたの組合を得ることができます:

type NeededUnionType = typeof list[number];  // 'a'|'b'|'c'.

お役に立てば幸いです。


これは、(タプルを使用した)ランタイムチェックと、型共用体を使用したコンパイル時チェックが必要な場合に頻繁に発生する問題に対する優れたソリューションです。言語に暗黙のタプルタイピングのサポートを追加する努力があるかどうか誰かが知っていますか?
ヨルゲンTvedt

ソリューションを試しましたが、機能しませんcont xs = ['a','b','c']; const list = tuple(...xs);
MiguelCarvajal19年

1
const xs = ['a','b','c']コンパイラはすでに拡張されxsstring[]おり、特定の値を完全に忘れているため、これで動作することは想定されていません。少なくともTS3.2の時点では、その動作を助けることはできません(as constただし、将来的には機能する表記法があるかもしれません)。とにかく、私は現状のままの答えは私がそれを作ることができるのと同じくらい正しいと思います(私はそこに['a','b','c']推測されていると述べていますstring[])ので、あなたがもっと何が必要かわかりません。
jcalz

3
誰かが何かを説明することができます [number]していlist[number]
Orelus

3
(typeof list)[number]...ではなく...として解析されますtypeof (list[number])。タイプT[K]は、キーが。であるプロパティのタイプを取得するルックアップタイプTですK。では(typeof list)[number](typeof list)キーがnumber。であるプロパティのタイプを取得しています。のような配列にtypeof list数値インデックス署名があるため、それらのnumberキーはすべての数値インデックスプロパティの和集合を生成します。
jcalz

15

TypeScript 3.4のアップデート:

TypeScript 3.4に登場する「constcontexts」と呼ばれる新しい構文により、示されているように関数呼び出しを必要としない、さらに単純なソリューションが可能になります。このPRに見られるように、この機能は現在レビュー中です。

つまり、この構文では、狭い型(つまり、またはの['a', 'b', 'c']代わりに型)を持つ不変の配列を作成できます。このようにして、以下に示すように、リテラルから共用体型を簡単に作成できます。('a' | 'b' | 'c')[]string[]

const MY_VALUES = <const> ['a', 'b', 'c']
type MyType = typeof MY_VALUES[number]

代替構文:

const MY_VALUES = ['a', 'b', 'c'] as const
type MyType = typeof MY_VALUES[number]

こんにちは、この質問を投稿した後、あなたの答えが見つかりました。);私はあなたがお答えしたい場合は、いくつかのカルマを獲得もらおうstackoverflow.com/questions/56113411/...
セバスチャン・ローバー

2

Arrayでこれを行うことはできません。

その理由は、変数をconstとして宣言しても、配列の内容は変更される可能性があるため、@ jonrsharpeはこれがランタイムであると述べています。

あなたが望むものを考えると、interface一緒に使用する方が良いかもしれませんkeyof

interface X {
    a: string,
    b: string
}

type Y = keyof X  // Y: 'a' | 'b'

またはenum

enum X { a, b, c }

特定のフィールドを除外する方法はありますか?たとえば、私はしたい場合はa、フィールドを...
neomib

あなたはそのために使うことができますPick<T, U>
unional

0

「定数」を格納するためにオブジェクトを使用する場合、これは同じアイデアを実装する方法です。

(keyOneとkeyTwoのタイプを文字列からリテラルに変更するには、「as const」に注意してください。)

const configObj = {
  keyOne: 'literalTypeValueOne' as const,
  keyTwo: 'literalTypeValueTwo' as const,
};

const typeValues = [configObj.keyOne, configObj.keyTwo] as const;
type MyType = typeof typeValues[number];
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.