Reputation: 121
I created a data.
type PenType = {
color: string
}
type PencilType = {
darkness: string
}
const data: {
pen: PenType,
pencil: PencilType
} = {
pen: {
color: "blue",
},
pencil: {
darkness: "2B"
}
};
type DataKeys = keyof typeof data;
I now have Object data with keys and values. I did create a function to get value from the data.
type MyReturnType = PenType | PencilType;
const getMyData = (keyToGet: DataKeys): MyReturnType => {
return data[keyToGet];
}
const finalData = getMyData('pen');
console.log(finalData);
This works completely fine. But the issue is, I want to get correct type in my finalData
. Since I have tried to access pen, I want return type to be PenType
, not PenType | PencilType
Is there any way to achieve this?
Sandbox link: https://codesandbox.io/s/typescript-playground-export-forked-hnle7p?file=/index.ts
Upvotes: 2
Views: 543
Reputation: 328262
If you explicitly annotate the return type to be PenType | PencilType
, then that's what the function will return no matter what.
If, instead, you want the compiler to keep track of the literal type of the value passed in as keyToGet
, you need getMyData()
to be generic in that type, with a generic type parameter as follows:
const getMyData = <K extends DataKeys>(keyToGet: K) => {
return data[keyToGet];
}
Here, getMyData
is generic in K
, a type parameter constrained to be assignable to DataKeys
, and the type of the keytoGet
function parameter.
I didn't annotate the return type explicitly. Instead, performing the indexing operation data[keyToGet]
and returning it means the returned type is inferred by the compiler to be a generic indexed access type:
/* {
pen: PenType;
pencil: PencilType;
}[K] */
So when you call getMyData('pen')
, K
is inferred as "pen"
, and then the return type will be {pen: PenType; pencil: PencilType}["pen"]
, an indexed access type that evaluates to PenType
:
const finalData = getMyData('pen');
// const finalData: PenType
console.log(finalData.color.toUpperCase()); // "BLUE"
Upvotes: 2