How to get the all types of all the props of interface into one type variable in TypeScript

Viewed 36

I am building a web application with Typescript. In my code, I got into a situation where I need to get all the types of every prop of an object/interface into a type variable.

I have an interface with the following code:

interface ProductForm {
    name: string;
    id: number | string;
    categoryId: number;
    status: ProductStatus // enum
}

As you can see, the above interface has 4 props and they have different types.

I want to have a function as follows:

const updateProductFormField = (name: keyof ProductForm, value: any) => {
   // update the field
}

As you can see in the above code, the function first parameter, name must be one of the props of the ProductForm interface. The second argument has type, any which I am trying to get rid of. The value must be one of the type of types of the props of ProductForm interface.

Basically I am trying to get all types of props of ProductForm into one variable like this:

type FormValueTypes = ProductForm['name'] | ProductForm['id'] | ProductForm['categoryId'] | ProductForm['status'];

Then use that type for second argument. But I am hardcoding in the fields in the code above? When a new field is added to the interface, I will have to change that variable too. Is that a more dynamic to achieve the same thing?

2 Answers

Try this.

interface ProductForm {
    name: string;
    id: number | string;
    categoryId: number;
    status: ProductStatus // enum
}

const updateProductFormField = <T extends keyof ProductForm>(name: T, value: ProductForm[T]) => {
   // update the field
}

Normally you'd get all types in values of an interface like below:

interface A {}

interface ProductForm {
    name: string;
    id: number | string;
    categoryId: number;
    status: ProductStatus;
}

const updateProductFormField = (name: keyof ProductForm, value: ProductForm[keyof ProductForm]) => {
   // Type of value here is string | number | ProductStatus
}

However this has the problem that you can do something like:

updateProductFormField('status', 42);

To avoid this you can make the function a generic:

const updateProductFormField = <T extends keyof ProductForm>(name: T, value: ProductForm[T]) => {
}

Playground link

Related