I am trying to create a generic interface for a function that accepts three argument. When filling in the first argument, the options of the second one should be in the scope of the first. The third argument should then be in scope of the second argument.
My current code looks like this:
type SettingActionCreator<T> = <
L extends T,
K extends keyof L,
C extends keyof L[K]
>(
type: K,
settingKey: keyof L[K],
settingValue: L[K][C]
)
export interface SomeSettings {
[Type.TypeA]: {
settingA: "value1" | "value2";
settingB: "value3 | "value4";
};
[Type.TypeB]: {
...
};
[Type.TypeC]: {
...
};
}
const setSomeSetting: SettingActionCreator<SomeSettings> = (
type,
settingKey,
settingValue
) =>
// do something
So when I want to call setSomeSetting with arguments I expect that my scope becomes smaller for each argument I pass into it.
If for example I fill in the first argument, than the SettingActionCreator makes sure that the second argument (settingKey) can only be settingA or settingB. So far everything works as expected.
setSomeSetting(Type.TypeA, ....) // <-- settingKey accepts "settingA" and "settingB"
But for the third argument I can't seem to solve it. When I set the first argument and the second argument I would expect that the third argument would only accept the union options within the chosen settingKey argument. But instead of that I get all options within Type.TypeA. So both the settingValues of settingA and settingB
With this code:
setSomeSetting(Type.TypeA, "settingA", "value3") // <-- settingValue should only accept "value1" or "value2"
I would expect an error like:
TS2345: Argument of type '"value3"' is not assignable to parameter of type `"value1" | "value2"
But instead I get no type errors because it accepts both the values of settingA and settingB.
Does someone have a suggestion for what I am doing wrong?
settingAandsettingBis because they are all the values that fit the type system you've described. There's no way to narrow it down any further than that because that would require runtime information that doesn't exist when typescript is parsing. I suggest you rework your design so the typing system is less nested, or maybe consider just throwing a runtime error for the final option