web-dev-qa-db-ja.com

タイプスクリプトのレコードタイプは何ですか?

TypescriptでRecord<K, T>はどういう意味ですか?

TypeScript 2.1ではRecord型が導入されました。これを例で説明します。

// For every properties K of type T, transform it to U
function mapObject<K extends string, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>

TypeScript 2.1 を参照してください。

そして、 高度な型 のページでは、その定義はRecordReadonly、およびPartialと並んで、マップ型の見出しの下にPickがあります。

type Record<K extends string, T> = {
    [P in K]: T;
}

Readonlyでは、PartialとPickは準同型であり、Recordはそうではありません。 Recordは準同型ではないという1つの手がかりは、プロパティをコピーするのに入力タイプを使用しないことです。

type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>

以上です。上記の引用の他に、 typescriptlang.org に関するRecordについての他の言及はありません。

質問

  1. 誰かがRecordとは何かの簡単な定義を与えることができますか?

  2. Record<K,T>は、単に「このオブジェクトのすべてのプロパティの型がTになる」ということを意味するのでしょうか。 Kは何らかの目的を持っているので、おそらくすべてのプロパティではないでしょう...

  3. Kジェネリックは、オブジェクト上でKではない追加のキーを禁止していますか。それとも、それらを許可し、それらのプロパティがTに変換されていないことを示していますか?

  4. 与えられた例では:

    type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
    

    これはこれとまったく同じですか?

    type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
    
55
Matthias Dailey
  1. 誰かがRecordとは何かの簡単な定義を与えることができますか?

Record<K, T>は、プロパティキーがKで、プロパティ値がTであるオブジェクト型です。つまり、keyof Record<K, T>Kと等価であり、Record<K, T>[K]は(基本的に)Tと等価です。

  1. Record<K,T>は、単に「このオブジェクトのすべてのプロパティの型がTになる」ということを意味するのでしょうか。 Kは何らかの目的を持っているので、おそらくすべてのオブジェクトではありません...

お気づきのとおり、Kには、プロパティキーを特定の値に制限するという目的があります。すべての可能な文字列値のキーを受け入れたい場合は、Record<string, T>のようなことをすることができますが、そのための慣用的な方法は インデックスシグネチャを使うことです{ [k: string]: T }のように。

  1. Kジェネリックは、オブジェクト上でKではない追加のキーを禁止していますか。それとも、それらを許可し、それらのプロパティがTに変換されていないことを示していますか?

追加のキーを厳密に「禁止」するわけではありません。結局のところ、値はその型の中で明示的に言及されていないプロパティを持つことが一般的に許可されています。

declare const x: Record<"a", string>;
x.b; // error, Property 'b' does not exist on type 'Record<"a", string>'

そしてそれはそれらを 過剰なプロパティ として扱い、それらは時々拒絶されます:

declare function acceptR(x: Record<"a", string>): void;
acceptR({a: "hey", b: "you"}); // error, Object literal may only specify known properties

そして時々受け入れられる:

const y = {a: "hey", b: "you"};
acceptR(y); // okay
  1. 与えられた例では:

    type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
    

    これはこれとまったく同じですか?

    type ThreeStringProps = {prop1: string, prop2: string, prop3: string}
    

はい!

それが役立つことを願っています。がんばろう!

70
jcalz

レコードを使用すると、Unionから新しいタイプを作成できます。 Unionの値は新しい型の属性として使用されます。

たとえば、私はこのような連合があるとします。

type CatNames = "miffy" | "boris" | "mordred";

これで、すべての猫に関する情報を含むオブジェクトを作成したいと思います。CatNameUnionの値をキーとして使用して、新しい型を作成できます。

type CatList = Record<CatNames, {age: number}>

このCatListを満たすには、次のようなオブジェクトを作成する必要があります。

const cats:CatList = {
  miffy: { age:99 },
  boris: { age:16 },
  mordred: { age:600 }
}

あなたは非常に強い型安全を得ます:

  • 私が猫を忘れた場合、私はエラーになります。
  • 許可されていない猫を追加すると、エラーになります。
  • 後でCatNameを変更すると、エラーが発生します。 CatNamesは別のファイルからインポートされ、多くの場所で使用されている可能性があるため、これは特に便利です。

実世界のReactの例.

私は最近これを使ってStatusコンポーネントを作成しました。コンポーネントはステータスプロップを受信して​​からアイコンをレンダリングします。説明のために、ここではコードをかなり単純化しました。

私はこのような組合を持っていました:

type Statuses = "failed" | "complete";

私はこれを使って次のようなオブジェクトを作成しました:

const icons: Record<
  Statuses,
  { iconType: IconTypes; iconColor: IconColors }
> = {
  failed: {
    iconType: "warning",
    iconColor: "red"
  },
  complete: {
    iconType: "check",
    iconColor: "green"
  };

それから、オブジェクトからプロップに要素を分解することによってレンダリングすることができます。

const Status = ({status}) => <Icon {...icons[status]} />

ステータスの共用体が後で拡張または変更された場合、私は自分のStatusコンポーネントがコンパイルに失敗することを知っていて、すぐに修正できるというエラーが出ます。これにより、アプリにエラー状態を追加することができます。

実際のアプリには、複数の場所で参照される数十のエラー状態があるため、このタイプの安全性は非常に役立ちました。

2
superluminary