環境: "typescript": "^4.4.4"
{[key in Union]: value type}
で定義できる
// この配列の値がキーになるオブジェクトの型を作りたい const luminas = ['OzoraAkari', 'HikamiSumire', 'ShinjoHinaki'] as const; type LuminasValues = typeof luminas[number]; // => LuminasValues = type LuminasValueType = "OzoraAkari" | "HikamiSumire" | "ShinjoHinaki"; type Luminas = { [key in LuminasValues]: any; } /* => type Luminas = { OzoraAkari: any; HikamiSumire: any; ShinjoHinaki: any; } */
interface だとエラーになる
[key in LuminasValues]
の部分がエラーになる
A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.
A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
/* A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.ts(1169) A computed property name must be of type 'string', 'number', 'symbol', or 'any'.ts(2464) */ interface ILuminas { [key in LuminasValues]: any; }
Record<Keys, Type>
を使うと簡単に書ける
Constructs an object type whose property keys are
Keys
and whose property values areType
. This utility can be used to map the properties of a type to another type.
cf. TypeScript: Documentation - Utility Types
const luminas = ['OzoraAkari', 'HikamiSumire', 'ShinjoHinaki'] as const; type LuminasValues = typeof luminas[number]; // => LuminasValues = type LuminasValueType = "OzoraAkari" | "HikamiSumire" | "ShinjoHinaki"; type Luminas = Record<LuminasValues, any> /* => type Luminas = { OzoraAkari: any; HikamiSumire: any; ShinjoHinaki: any; } */
note. interface はプロパティを動的に定義できないケースがある
interface A { [key: string]: any; } // => string の key なんでもは OK interface B { [key: string | number]: any; } // => key が Union 型なのも OK interface C { [key: 'A' | 'B']: any; } // => Error // => An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead. interface D { [key in 'A' | 'B']: any } // => Error // => A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.
Union型を key にするのはOK だけど [key: 'A' | 'B']
のようなリテラル型のUnionでのプロパティ設定はエラーになる
An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead.
プロパティ決まってるなら {A: any; B: any;}
のように書けって事っぽい。
[key: 'A' | 'B']
のようなリテラル型のUnionでのプロパティ設定は type でも同じエラーになる
type C = { [key: 'A' | 'B']: any; } // => An index signature parameter type cannot be a literal type or generic type. Consider using a mapped object type instead. type D = { [key in 'A' | 'B']: any; } // => OK
interface で定義しようとして苦しんだ。
[参考]