Convert a property of type literal (label type) to a primitive type. Master advanced TypeScript type manipulation in this medium-level challenge on TypeScriptPro.
In this medium-level challenge, you'll implement ToPrimitive<T> which deeply converts all literal types in an object to their corresponding primitive types (e.g., 'Tom' becomes string, 30 becomes number).
Convert a property of type literal (label type) to a primitive type.
For example
type X = {
name: 'Tom',
age: 30,
married: false,
addr: {
home: '123456',
phone: '13111111111'
}
}
type Expected = {
name: string,
age: number,
married: boolean,
addr: {
home: string,
phone: string
}
}
type Todo = ToPrimitive<X> // should be same as `Expected`Change the following code to make the test cases pass (no type check errors).
type PersonInfo = {
name: 'Tom'
age: 30
married: false
addr: {
home: '123456'
phone: '13111111111'
}
hobbies: ['sing', 'dance']
readonlyArr: readonly ['test']
fn: () => any
}
type ExpectedResult = {
name: string
age: number
married: boolean
addr: {
home: string
phone: string
}
hobbies: [string, string]
readonlyArr: readonly [string]
fn: Function
}
type cases = [Expect<Equal<ToPrimitive<PersonInfo>, ExpectedResult>>]
Unlock 102+ medium, hard, and extreme challenges to master advanced TypeScript.
One-time payment. Lifetime access.
type Primitive<T> = T extends string
? string
: T extends number
? number
: T extends boolean
? boolean
: T extends Function
? Function
: T extends object
? ToPrimitive<T>
: T
type ToPrimitive<T> = T extends readonly any[]
? { [K in keyof T]: Primitive<T[K]> }
: {
[K in keyof T]: T[K] extends object ? ToPrimitive<T[K]> : Primitive<T[K]>
}How it works:
Primitive<T> is a helper type that maps a single type to its primitive equivalent. It checks, in order: string literals to string, number literals to number, boolean literals to boolean, Function types to Function, and recursively processes nested objects with ToPrimitive.ToPrimitive<T> handles the top-level structural recursion. It first checks if T is a tuple/array using T extends readonly any[], and if so, maps over it while preserving the tuple structure (including readonly modifiers) by using { [K in keyof T]: Primitive<T[K]> }.ToPrimitive; otherwise it converts the value with Primitive.Primitive matters: boolean must be checked after string and number but before object, because boolean is not an object type. Function must be checked before object because functions are objects.This challenge helps you understand recursive type transformation and literal-to-primitive type widening and how to apply these concepts in real-world scenarios.
This challenge is originally from here.