DEV Community

Cover image for How to dynamically get the interface or type alias property value types from conditional types in TypeScript?
MELVIN GEORGE
MELVIN GEORGE

Posted on • Originally published at melvingeorge.me

How to dynamically get the interface or type alias property value types from conditional types in TypeScript?

Originally posted here!

To dynamically get an interface or type alias property value type from conditional types, you can use the infer keyword followed by declaring a generic type name wherever you need to get the value from and then using that value as the truthy value in the conditional type check in TypeScript.

TL;DR

// a generic conditional type
type GetSalaryType<T> = T extends { salary: infer value } ? value : never;

// an interface where the salary
// property is `string` type
interface Person {
  name: string;
  salary: string;
}

// an interface where the salary
// property is `number` type
interface Person2 {
  name: string;
  salary: number;
}

// an interface where the salary
// property is an `array of string` type
interface Person3 {
  name: string;
  salary: string[];
}

// get the type of the `salary` property
// from the all the above interfaces
type SalaryType = GetSalaryType<Person>; // string
type SalaryType2 = GetSalaryType<Person2>; // number
type SalaryType3 = GetSalaryType<Person3>; // string[]
Enter fullscreen mode Exit fullscreen mode

For example, first, let's consider a small scenario where we need to choose between the type string and the number type by checking if the interface or the type alias contains a property called salary.

So in this case the better way is to use a conditional type and make the whole type into a generic type alias.

It can be done like this,

// a generic conditional type
type GetSalaryType<T> = T extends { salary: string } ? string : never;
Enter fullscreen mode Exit fullscreen mode

Now let's create an interface called Person with properties called name and salary having the type of string.

It can be done like this,

// a generic conditional type
type GetSalaryType<T> = T extends { salary: string } ? string : never;

// a simple interface called Person
interface Person {
  name: string;
  salary: string;
}
Enter fullscreen mode Exit fullscreen mode

Now let's pass the Person interface to the GetSalaryType generic conditional type like this,

// a generic conditional type
type GetSalaryType<T> = T extends { salary: string } ? string : never;

// a simple interface called Person
interface Person {
  name: string;
  salary: string;
}

// get the type of the `salary` property
// from the `Person` interface
type SalaryType = GetSalaryType<Person>; // string
Enter fullscreen mode Exit fullscreen mode

Now if you hover over the SalaryType type you can see that the type is of string that is correct and satisfies our needs in this case.

But we know that salary can have many forms like string, number or even an array of salaries. If we pass a type where the salary type is number to the GetSalaryType then also we will get the type of string in the SalaryType type alias which may not suit our needs.

So to make the GetSalaryType conditional generic type into a more flexible type let's use the infer keyword after the salary property in the condition followed by a generic type name. Let's name the generic type name as value and then use that as the truthy value in the condition.

It can be done like this,

// a generic conditional type
type GetSalaryType<T> = T extends { salary: infer value } ? value : never;

// a simple interface called Person
interface Person {
  name: string;
  salary: string;
}

// get the type of the `salary` property
// from the `Person` interface
type SalaryType = GetSalaryType<Person>; // string
Enter fullscreen mode Exit fullscreen mode

Now let's make 2 more interfaces called Person2 and Person3 where the salary property is of number type and an array of strings type respectively and then pass that to the GetSalaryType conditional generic type.

It can be done like this,

// a generic conditional type
type GetSalaryType<T> = T extends { salary: infer value } ? value : never;

// an interface where the salary
// property is `string` type
interface Person {
  name: string;
  salary: string;
}

// an interface where the salary
// property is `number` type
interface Person2 {
  name: string;
  salary: number;
}

// an interface where the salary
// property is an `array of string` type
interface Person3 {
  name: string;
  salary: string[];
}

// get the type of the `salary` property
// from the all the above interfaces
type SalaryType = GetSalaryType<Person>; // string
type SalaryType2 = GetSalaryType<Person2>; // number
type SalaryType3 = GetSalaryType<Person3>; // string[]
Enter fullscreen mode Exit fullscreen mode

As you can see that the SalaryType, SalaryType2, and the SalaryType3 have different types according to the interfaces passed to the GetSalaryType conditional generic type.

We have dynamically got the interface property value type from conditional types successfully in TypeScript. Yay 🥳!

See the above code live in codesandbox.

That's all 😃!

Feel free to share if you found this useful 😃.


Top comments (0)