简体   繁体   中英

Getting type of Object's value from key

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 PenType | PencilType

Is there any way to achieve this?

Sandbox link: https://codesandbox.io/s/typescript-playground-export-forked-hnle7p?file=/index.ts

If you explicitly annotate the return type to be PenType | PencilType 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"] {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"

Playground link to code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM