Given the following scenario:
type Action =
| { type: 'FOO' }
| { type: 'BAR' }
type Rule = {
target: string | string[],
consequence: (action:Action) => void
}
const rule1:Rule = {
target: 'FOO',
consequence: action => console.log(action) // { type: 'FOO' }
}
const rule2:Rule = {
target: ['FOO', 'BAR'],
consequence: action => console.log(action) // { type: 'FOO' } | { type: 'BAR' }
}
The action can be dispatched (eg with redux) and the rule can react to it. When the target matches the action.type then the consequence gets executed with the matching action.
I want that the rules consequence infers the right type. This can be done somehow by the target . But I don't know how. My current approach:
type Rule<Action> = {
target: string | string[],
consequence: (action:Action) => void
}
const rule:Rule<{ type: 'FOO' }> = ...
But I need a way where I can write
const rule:Rule<{ type: 'FOO' } | { type: 'BAR' }> = ...
and the correct type gets inferred by the rules target
This is the best I could figure out. You'll have to abandon target
being a single value, and rely on it always being an array, even if that array has a single element. There might be a way to get it to work with function overloads, but I couldn't get it to work.
type ActionType = "FOO" | "BAR";
type Action<T extends ActionType> = { type: T };
function createRule<T extends ActionType[]>(target: T) {
return {
target,
consequence: (action: Action<T[number]>) => console.log(action)
};
}
const foo = createRule(["FOO"]);
const bar = createRule(["FOO", "BAR"]);
foo.consequence({ type: "FOO" });
foo.consequence({ type: "BAR" }); // nope
bar.consequence({ type: "FOO" });
bar.consequence({ type: "BAR" });
bar.consequence({ type: "BAZ" }); // nope
https://codesandbox.io/s/dawn-wildflower-03cbq?file=/src/index.ts
Using a function to create the rule lets you use generics without having to repeat yourself by specifying it as both a type and a value every time you create a new rule.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.