Typescript:オブジェクトの配列から共用体型を派生させる


8

型強制された項目の配列を宣言し、それから共用体型を導出できるようにしたいと思います。このパターンは、配列の項目にタイプを明示的に指定しない場合に機能します。私はそれを最もよく説明する方法がわからないので、ここに例があります:

例1

type Pair = {
  key: string;
  value: number;
};

const pairs: ReadonlyArray<Pair> = [
  { key: 'foo', value: 1 },
  { key: 'bar', value: 2 },
] as const;

type Keys = typeof pairs[number]['key']

例2

type Data = {
  name: string;
  age: number;
};

const DataRecord: Record<string, Data> = {
  foo: { name: 'Mark', age: 35 },
  bar: { name: 'Jeff', age: 56 },
} as const;

type Keys = keyof typeof DataRecord;

を使用する場合のキーの導出例を以下に示しますas const。これと同じ動作が必要ですが、配列が明示的に型指定されています。

const pairs = [
  { key: 'foo', value: 1 },
  { key: 'bar', value: 2 },
] as const;

type Keys = typeof pairs[number]['key']; // "foo" | "bar"

キーの望ましい値: "foo"|"bar"

キーの実際の値: string


4
あなたがしようとしている方法でこれを動的に行うことはできないと思います、ランタイム値をコンパイル時の型と融合しています。型のkey属性にPair必要な型を指定する必要があります。そうすると、記述したとおりに機能するはずです。
Jared Smith

4
これはあなたの質問に答えますか?
Typescriptは

@JaredSmithこれは実行時に問題になりません。これを使用して、実行中に変化しない任意の数の値を宣言しています。これは、型宣言でkey: "foo" | "bar"を設定することと同じです。
ベン

「これは実行時に問題にならないはずです」--- typescriptには実行時がないため、実行時に実行すること問題です。
zerkms

1
@Benを使用すると、より具体的にすることができます。変更可能な参照型からプルされたプロパティのタプルを使用して、不変のプリミティブのタプルを使用する場合と同じ方法でこれを行うことはできないと思います。言うことはできますpossibleKeys = ['foo', 'bar'] as const; type Keys = typeof possibleKeys[number]; type Pair = { key: Keys, value: number };が、それでも可能なキーを明示的に列挙する必要があります。
Jared Smith

回答:


3

変数の場合、コンパイラーに初期化から型を推測させるか、明示的に書き込むことができます。ご存じのように明示的に書き込む場合、初期化値は注釈と照合されますが、初期化子の実際のタイプは変数のタイプに影響しません(したがって、必要なタイプ情報が失われます)。コンパイラにそれを推測させると、タイプを特定のインターフェースに準拠するように制約することはできなくなります(望んでいるように)

このための解決策は、ジェネリック関数を使用して、値を制約し、その実際のタイプを推測することです。

type Pair = {
  key: string;
  value: number;
};
function craetePairsArray<T extends readonly Pair[] & Array<{key: V}>, V extends string>(...args: T) {
    return args
}

const pairs = craetePairsArray(
  { key: 'foo', value: 1 },
  { key: 'bar', value: 2 },
)

type Keys1 = typeof pairs[number]['key']

type Data = {
  name: string;
  age: number;
};

function craeteDataObject<T extends Record<string, Data>>(arg: T) {
    return arg;
}
const DataRecord = craeteDataObject({
  foo: { name: 'Mark', age: 35 },
  bar: { name: 'Jeff', age: 56 },
})

type Keys2 = keyof typeof DataRecord;

遊び場リンク

注:配列の場合は、コンパイラーを少し強化して、の文字列リテラル型を推測する必要がありますkey。したがって、全体& Array<{key: V}>Vです。string


1
ありがとうございました!これはまさに私が必要としたものです!
ベン

2

通常のアプローチは次のとおりです。

  • pairs明示的なタイプを省略してTSにのタイプを推測させますReadonlyArray<Pair>回答を参照)
  • 与えるkeyPairタイプ"foo"|"bar"

あなたがいる場合はありませんこれを行うにしたい、そして、あなたの鍵を推測するための唯一の方法の種類を制限するには、pairsヘルパー関数を使用することです。Pairタイプは、与えられた保存することが一般的な作られるkey文字列リテラルの型を。IIFEを使用して、割り当てをコンパクトにすることができます。

type Pair<K = string> = {
    key: K;
    value: number;
};

const pairs = (<T>(p: readonly Pair<T>[]) => p)([
    { key: 'foo', value: 1 },
    { key: 'bar', value: 2 },
] as const) // readonly Pair<"foo" | "bar">[]

type Keys = typeof pairs[number]['key'] // "foo" | "bar"

遊び場

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.