Reputation: 3022
I'm trying to wrap my head around conditional mapped types. If I have a type defined as:
type StringyProps<T> = { [K in keyof T]: T[K] extends string ? K : never }[keyof T];
What's the [keyof T]
construct at the end doing? How can find documentation about what you can do with that?
Also, I've written a function:
function getString<T>(thing: T, prop: StringyProps<T>): string {
return thing[prop] as string;
}
If I have an interface as follows:
interface Something {
name: string,
id: string,
age: number,
weight: number
}
I get the following compile time errors:
console.log(getString(pippy, "name")); // ok
console.log(getString(pippy, "age")); // age is not assignable to parameter of type "name" | "id"
That's pretty awesome, but my function won't compile because it may be a mistake to assign the StringyProp's value to a string. If I change the return to return thing[prop] as unknown as string
it returns the correct value.
How can I construct this so that I don't have to assert unknown and re-assert string?
Upvotes: 1
Views: 336
Reputation: 249706
Typescript can't follow the fact that StringyProps<T>
represenst only string
prfoperty keys. The best solution is to use a type assertion:
function getString<T>(thing: T, prop: StringyProps<T>): string {
return thing[prop] as unknown as string;
}
You can also change the types around a little bit, but intelisense will not suggest keys anymore so I don't really think it's worth it, call site experience is more important:
function getString<K extends PropertyKey>(thing: Record<K, string>, prop: K): string {
return thing[prop]; // ok no assertion
}
console.log(getString(pippy, "name")); // ok
console.log(getString(pippy, "age")); //err
Upvotes: 1