I am looking to run a specific handler for an input based on the type
property of the input. The setup is as follows:
type MyObjectType = "alpha" | "beta";
interface MyAlphaObject {
value: number;
type: "alpha";
}
interface MyBetaObject {
value: string;
type: "beta";
}
type MyObject = MyAlphaObject | MyBetaObject;
const getValueOfAlpha = ({ value }: MyAlphaObject) => value;
const getValueOfBeta = ({ value }: MyBetaObject) => value;
type MyObjectTypeOf<T extends MyObjectType> = Extract<MyObject, { type: T }>;
type MyObjectValueOf<T extends MyObjectType> = MyObjectTypeOf<T>["value"];
type HandlerFunc<T extends MyObjectType> = (value: MyObjectTypeOf<T>) => MyObjectValueOf<T>;
const handlers: { [T in MyObjectType]: HandlerFunc<T> } = {
alpha: getValueOfAlpha,
beta: getValueOfBeta,
};
This setup works well when the type
is already known at compile time, like:
✅ This example will work
const alpha: MyAlphaObject = {
type: "alpha",
value: 25
}
const handler = handlers["alpha"]
console.log(alpha)
❌ However, it fails if the type is only determined at runtime, such as:
const choices = ["alpha", "beta"] as const
const alpha: MyAlphaObject = {
type: "alpha",
value: 25
}
const beta: MyBetaObject = {
type: "beta",
value: "text value"
}
const randomChoice = choices[Math.round(Math.random() * 10)%2]
const handler = handlers[randomChoice]
console.log(handler(alpha))
Link to code playground: https://tsplay.dev/wOQgRm
Question:
- Is there a way to make this work?
- Are there more efficient alternatives?
Edit 2024-10-29 15:34 EST
In addition, achieving this is possible using:
- long chains of ternaries
- if-else statements
- switch cases
- forced assertions
For instance, the following approach is viable:
const result = randomChoice === "alpha" ? handlers[randomChoice](alpha) : randomChoice === "beta" ? handlers[randomChoice](beta) : null
console.log(result)
I am exploring options that can evade these methods if feasible.