Reputation: 11
I'm reading from a data source where I know the return type for each lookup key. I defined this in the type DataLayout
.
I want to make the function getItem()
generic and get the correct return type accordingly.
type DataLayout = {
a: string
b: number
}
const getItem = <T extends Record<string, unknown>>(key: string & keyof T) => {
return getExternalItem(key) as T[typeof key]
}
const result = getItem<DataLayout>('a')
but result
is of type string | number
.
How do I make it string
only? Is this possible?
Upvotes: 1
Views: 74
Reputation: 748
In addition to captain-yossarian's anwer, I like to use a class for this. Also, I added an extra check to the getItem
function to make sure that getItem('c')
will give a compiler error.
type DataLayout = {
a: string;
b: number;
};
class Entity<T extends Record<string, unknown>> {
getItem<K extends keyof T>(key: K & keyof T): T[K] {
return null as any;
}
}
const ent = new Entity<DataLayout>();
// type of result is string
const result = ent.getItem('a');
// this will give a compiler error:
ent.getItem('c');
Upvotes: 1
Reputation: 33091
This can be done in a bit different way:
type DataLayout = {
a: string
b: number
}
declare var data: DataLayout;
const dataLayout = <Obj,>(obj: Obj) => <Prop extends keyof Obj>(prop: Prop) => obj[prop]
const withData = dataLayout(data)
const getItem = withData('a') // string
const getItem2 = withData('b') // number
In 79.8% cases, you should not use explicit generic, TS should infer it from some value
Upvotes: 1