0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TypeScriptの個人メモ

Posted at

この記事について

TypeScriptで開発をする中で忘れたくない内容を個人的にメモしました。

Object.keysの戻り値を文字リテラルユニオンの型にする

文字リテラルユニオンの型とは("apple"|"orange"|"banana")[]のような形式で、appleかorangeかbananaのいずれかの文字リテラルを値にもつ配列の型のこと。

Object.keys()の戻り値の型はstring[]になる。これはオブジェクトのキーに指定できる型がstring型とnumber型の両方あることが原因。

これで生じる不都合としてはkeyの値をもとにしたSwitch文による条件分岐とか、下の例のような、元のオブジェクトとkeyから値を取得しようとしたりすると、エラーになること。

const testObj = {
  name: "shun",
  food: "ramen",
  hobby: "volleyball",
};

// testObeKeys:string[]
const testObeKeys = Object.keys(testObj);

// エラー:型 'string' の式を使用して型 '{ name: string; food: string; hobby: string; }' にインデックスを付けることはできないため、要素は暗黙的に 'any' 型になります。
// 平たくいうと"testObj"の値をキー指定で取得する時は、文字リテラルにしてね。というエラー(string型だと、キーに無い値も指定できてしまうから)
const rtn = testObeKeys.map((key) => {
  return {
    key: `NEW_${testObj[key]}`,
  };
});

上の例の場合、Object.entryを使えば解決するけど、今回はObject.keysの戻り値の型をstring[]型から文字リテラルユニオン配列型に変える

// 引数のオブジェクトのキーを文字リテラルユニオンの配列型で返す関数
const getKeys = <T extends { [key: string]: unknown }>(obj: T): (keyof T)[] => {
  return Object.keys(obj);
};

const keys = getKeys(testObj);

const rtn = keys.map((key) => {
  return {
    key: `NEW_${testObj[key]}`,
  };
});

分解して解説します。
まず大前提として、文字リテラルユニオンの配列型にするのだから、そもそもキーにnumber型が存在するオブジェクトは受け付けないようにする。
それをやっているのがここ。

// extendsを使い、キーがstring型のobjのみ引数として受け付けるようにする。
<T extends { [key: string]: unknown }>(obj: T):

次にgetKeys関数の戻り値の型(keyof T)[]の部分。

// keyof Tの戻り値は"name" | "food" | "hobby"となる。それを()で閉じて、[]を付けると、
// ("name" | "food" | "hobby")[]となる。
(keyof T)[]

Object.keys(obj);は通常string[]型を返すけど、関数の戻り値の型として(keyof T)[]を指定することで、string[]型が(keyof T)[]型にキャストされる。
(厳密には、関数の戻り値の型を(keyof T)[]型に指定しているので、TypeScriptが(keyof T)[]型と型推論してくれる)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?