Advanced Typescript Questions - Conditional Types
In this post, we will go through some advanced Typescript Type concepts.
Hello, this is the fourth of my Typescript interview series. I also wrote a post of beginner questions, and two posts for intermediate questions - one, and two.
Q1 - Conditional Types
Given the following code
type Car = {
model: string
}
type House = {
sqft: number
}
function houseOrCar<K extends 'Car' | 'House'>(s: K): Car | House {
return s === 'Car' ? { model: 'hyundai' } : { sqft: 100_000 } as any
}
When we try to use the houseOrCar()
function, the resulting type is Car | House
as shown:
const car = houseOrCar('Car') // Car | House
const house = houseOrCar('House') // Car | House
How can we modify the type definitions such that the function houseOrCar()
returns an object of type Car
when input is 'Car'
and House
when the input is 'House'
?
/* DEFINE A TYPE HERE */
function houseOrCar<K extends 'Car' | 'House'>: /* CHANGE CODE HERE */ {
return s === 'Car' ? { model: 'hyundai' } : { sqft: 100_000 } as any
}
const car = houseOrCar('Car') // Car
const house = houseOrCar('House') // House
Answer
Use conditional types utility type.
type StringToType<T> = T extends 'Car' ? Car : T extends 'House' ? House : never
function houseOrCar<K extends 'Car' | 'House'>(s: K): StringToType<K> { return s === 'Car' ? { model: 'hyundai' } : { sqft: 100_000 } as any
}
Q2 never
filter
Given the following code
type Employee = {
name: string,
age: number,
weaknesses: never
}
How can we extract all the possible different types of possible value-types except never
?
type PossibleTypes = /* YOUR CODE HERE * /
// type PossibleTypes = string | number
Answer
Typescript removes never
whenever it has a union, so a simple keyof
operation will suffice.
type PossibleTypes = Employee[keyof Employee] // string | number
Q3 How to get properties of a specific type
Given the following code
type House = {
sqft: number,
address: string,
floors: number,
bedrooms: number,
builtAt: Date
}
We want to create a generic type such that we can extract properties of a specific type, as shown:
type NumberProperties = PropsOfType<House, number> // "sqft" | "floors" | "bedrooms"
type StringProperties = PropsOfType<House, string> // "address"
type DateProperties = PropsOfType<House, Date> // "builtAt"
Write a generic type PropsOfType
that can achieve the above.
Hint: the answers from the previous two questions above will help
Hint 1
Here is what the following code gets me.
type PropsOfTypeNumber = {
[K in keyof House]: House[K] extends number ? K : never
}
// type PropsOfTypeNumber = {
// sqft: "sqft";
// address: never;
// floors: "floors";
// bedrooms: "bedrooms";
// builtAt: never;
// }
We have a type where the keys are the same but the values are now the string representation of the key IF they are a number. 🤔 Otherwise they are never
. If only we could filter out those never
s…
And then make it generic.
Hint 2
Here is what the following code gets me.
type ValueOf<T> = T[keyof T]
type PropsOfTypeNumber = ValueOf<{
[K in keyof House]: House[K] extends number ? K : never
}>
// type PropsOfTypeNumber = "sqft" | "floors" | "bedrooms
We are now able to successfully filter out the never
s, as they are filtered out by Typescript unions.
Now we just need to make it generic… 🤔
Answer
type ValueOf<T> = T[keyof T]
type PropsOfType<T, P> = ValueOf<{
[K in keyof T]: T[K] extends P ? K : never
}>
type NumberProperties = PropsOfType<House, number> // "sqft" | "floors" | "bedrooms"
type StringProperties = PropsOfType<House, string> // "address"
type DateProperties = PropsOfType<House, Date> // "builtAt"
Great job! Hope you learned something from this.
Happy learning!