I have a working 'solution' but it's very ugly and I'm wondering if there's a cleaner one. The code I have written is something along the lines of the following, this accomplishes my goal of getting typescript to correctly infer the type of value
in each of the branches of the switch statment.
type Foo = {
key1: string
key2: number
key3: {message: string}
}
type FooProperty<Key extends keyof Foo> = {
key: Key,
value: Foo[Key],
}
type FooPropertyData = FooProperty<'key1'> | FooProperty<'key2'> | FooProperty<'key3'>
const func = (change: FooPropertyData) => {
switch (change.key) {
case "key1": {
return change.value.toUpperCase()
}
case "key2": {
return change.value * 8
}
case "key3": {
return change.value.message
}
}
}
However this requires you to manually add every key of Foo
to the FooPropertyData
type. which is clearly not ideal. My first thought would be to do something like:
type FooPropertyData = FooProperty<keyof Foo>
But this loses type safety. Is there a better way to do this?
Apologies if the title is misleading I'm new to generic types and am not exactly sure how best to word it.
CodePudding user response:
The solution is to make TypeScript use each constituent of keyof Foo
separately:
type FooPropertyData<T extends keyof Foo = keyof Foo> = T extends T ? FooProperty<T> : never;
This phenomenon can be demonstrated in the following:
type All<T> = Set<T>;
type Each<T> = T extends T ? Set<T> : never;
type AllIn = All<"1" | "2">; // Set<"1" | "2">
type EachIn = Each<"1" | "2">; // Set<"1"> | Set<"2">