Object.keys
でdictからkeyを取り出そうとしたときに、stringになってしまう問題の対処法
export type Drinks = "beer" | "wine" | "cocktail";
const drinkPrices: { [key in Drinks]: number } = {
beer: 500,
wine: 800,
cocktail: 600,
};
const drinkQuantities: { [key in Drinks]: number } = {
beer: 4,
wine: 2,
cocktail: 1,
};
const drinkList = Object.keys(drinkPrices).map((key) => {
return {
name: key,
// ! No index signature with a parameter of type 'string' was found on type '{ beer: number; wine: number; cocktail: number; }'.
price: drinkPrices[key],
// ! No index signature with a parameter of type 'string' was found on type '{ beer: number; wine: number; cocktail: number; }'.
quantity: drinkQuantities[key],
};
});
対処法1. Object.keysの型を上書きする
src/types/ObjectKeys.d.ts
などを作成し、以下のように型を上書きします
type ObjectKeys<T> = T extends { [key: string]: unknown } ? (keyof T)[] : never;
interface ObjectConstructor {
keys<T>(o: T): ObjectKeys<T>;
}
これでObject.keys
を使用する場合は自動的に推論が当たるようになります
既存の書き方を変えずに型だけ変えられるので、一番おすすめのやり方になります。
対処法2. util関数を作成する
Object.keys
のラッパー関数をutilityとして作成し、Object.keys
の代わりに使用する方法です
const objectKeysWithTypes = <T extends { [key: string]: unknown }>(
obj: T
): (keyof T)[] => {
return Object.keys(obj);
};
暗黙のうちに型解決を行う1に比べて、型推論を行っていることを明示できるというメリットはありますが、好みの範疇かなと思います。
対処法3. asで注釈をつける
as
を用いてObject.keysの結果に無理やり型を付ける方法です
export type Drinks = "beer" | "wine" | "cocktail";
const drinkPrices: { [key in Drinks]: number } = {
beer: 500,
wine: 800,
cocktail: 600,
};
const drinkQuantities: { [key in Drinks]: number } = {
beer: 4,
wine: 2,
cocktail: 1,
};
const drinkList = (Object.keys(drinkPrices) as Drinks[]).map((key) => {
return {
name: key,
price: drinkPrices[key],
quantity: drinkQuantities[key],
};
});
Object.keys
を用いるたびにas
句を使わないといけない上に、Object.keys
の引数の型が変わったことを検知できないため、変更に弱くなります。
納期に追われている時以外は使用しない方がいいです
コメント