switch(key)
のkey に応じて、value
の型を解決させたい
Union
基本的には、複数の型を作ってUnionで定義してあげることになるかと思う。
// こんな感じ
type IncreaseAction = { type: "INCREASE"; payload: { value: number } }
type DecreaseAction = { type: "DECREASE"; payload: { value: number } }
type DebugAction = { type: "DEBUG"; payload: { fn: () => void } }
type Action = IncreaseAction | DecreaseAction | DebugAction;
const runner = (action: Action) => {
switch(action.type) {
case "INCREASE": {
return console.log(action.payload.value + 1);
}
case "DECREASE": {
return console.log(action.payload.value - 1);
}
case "DEBUG": {
return action.payload.fn();
}
}
}
Object.entires
ただ、1つのオブジェクトにkey,value がまとまってるときはObject.entries を使うことになる。ObjectEntiresを解決できる型を用意してあげればできる。
const attributes: Attributes = {
k1: "Hello",
k2: 100,
k3: () => console.log(":D"),
};
type Attributes = {
k1: string,
k2: number,
k3: () => void,
}
type AttributesPair = ObjectEntries<Attributes>;
const runner = (pair: AttributesPair) => {
const [key, value] = pair;
switch(key){
case "k1": {
// value の型が stringに解決する
return console.log(value, " World!")
}
case "k2": {
// value の型が numberに解決する
return console.log(value+11, "is 111.")
}
case "k3": {
// value の型が `() => void` に解決する
return value();
}
default: {
const _: never = key; // in order to detect ts check
throw new Error(`invalid data. ${_}`)
}
}
}
// ====================
// main.ts
// ====================
Object.entries(attributes).map((_pair: any) => {
const pair = _pair as AttributesPair;
runner(pair);
});
// =============
// Helper
// =============
// REF: https://github.com/type-challenges/type-challenges/issues/14052
// type RemoveUndefined<T> = [T] extends [undefined] ? T : Exclude<T, undefined>
// type ObjectEntries<T> = {
// [K in keyof T]-?: [K, RemoveUndefined<T[K]>]
// }[keyof T]
type ObjectEntries<T, U extends keyof T = keyof T> = U extends any ? [U, Exclude<T[U], undefined>] : never;