16259-medium-to-primitive

Back

// your answers
type Primitive = string | bigint | boolean | number | null | undefined
type TypeOf<T> = T extends Function
  ? Function
  : T extends { valueOf: () => infer P } ? P : never
type ToPrimitive<Obj> = {
  [K in keyof Obj]: Obj[K] extends (Function | Primitive)
    ? TypeOf<Obj[K]>
    : ToPrimitive<Obj[K]>
}

Solution by DevilTea #33117

type ToPrimitive<T> = {
  [P in keyof T]: T[P] extends string 
                    ? string 
                    : T[P] extends number
                      ? number
                      : T[P] extends boolean
                        ? boolean
                        : T[P] extends (unknown[] | readonly unknown[])
                          ? ToPrimitive<T[P]>
                          : T[P] extends () => unknown
                            ? Function
                            : keyof T[P] extends keyof T[P]
                              ? ToPrimitive<T[P]>
                              : T[P]
}

Solution by keyurparalkar #32749

type ToPrimitiveNonArray<T> = T extends number ? number : T extends string ? string : T extends boolean ? boolean : never
type ToPrimitiveArray<T> = T extends [infer A, ...infer B] ? [ToPrimitiveNonArray<A>, ...ToPrimitiveArray<B>] : []
type ToPrimitiveValue<T> = T extends Array<any> ? ToPrimitiveArray<T> : ToPrimitiveNonArray<T>
type ToPrimitive<T> = {
  [K in keyof T]: T[K] extends Record<string, any> ? ToPrimitive<T[K]> : ToPrimitiveValue<T[K]>
}

Solution by hwasurr #31431

type ToPrimitive = T extends number ? number : T extends string ? string : T extends boolean ? boolean : T extends bigint ? bigint : T extends symbol ? symbol : T extends null ? null : T extends undefined ? undefined : T extends () => any ? Function : T extends object ? { [P in keyof T]: ToPrimitive<T[P]> } : never ;

Solution by ArtDorfman #30768

type ToPrimitive<T> = {
  [K in keyof T]: T[K] extends (...args: never[]) => unknown 
    ? Function 
    : T[K] extends Record<any, any> | object 
    ? ToPrimitive<T[K]> 
    : T[K] extends { valueOf: () => infer P } 
    ? P 
    : T[K]
}

Solution by dreamluo-plus #30688

/* _____________ 你的代码 _____________ */

type ToPrimitive<T> = T extends object ?
  T extends Function ? 
    Function 
  : 
    {[Key in keyof T]: ToPrimitive<T[Key]>}
: 
  T extends { valueOf: () => infer P } ? 
    P 
  : 
    T

Solution by utranhost #30522

type ToPrimitive<T> = T extends object ? {
  [Key in keyof T] : ToPrimitive<T[Key]>;
} : (
  T extends { valueOf: () => infer P } ? P : T;
)

Solution by kanishev #29949

// your answers

type CheckPrimitive<U> = U extends number ? number : U extends boolean ? boolean : U extends string ? string : U extends symbol ? symbol : U extends bigint ? bigint  : never;

type ToPrimitive<T> = T extends Function ? Function : T extends object ? {
  [K in keyof T]: ToPrimitive<T[K]> 
}: CheckPrimitive<T>

Solution by kerolossamir165 #29021

type Primitive = number | boolean | string | bigint | symbol;

type ToPrimitive<T, P = Primitive> = T extends (...args: any[]) => unknown
  ? Function
  : T extends Record<keyof any, any>
  ? {
      [K in keyof T]: ToPrimitive<T[K]>;
    }
  : P extends P
  ? T extends P
    ? P extends boolean
      ? boolean
      : P
    : never
  : never;

Solution by DoubleWoodLin #28864

  1. T extends object ? ... : ...:这个条件类型判断 T 是否是对象类型。
    • 如果 T 是对象类型,进入第一个分支。
    • 否则,进入第二个分支。
  2. 对象类型的处理:T extends (...args: never[]) => unknown ? Function : { [Key in keyof T]: ToPrimitive<T[Key]> }
    • 如果 T 是函数,返回 Function 类型。这是为处理对象类型中的函数类型定义。
    • 如果 T 不是函数,对 T 的每个属性进行递归求解,得到一个将 T 的所有属性转换为原始类型的新映射类型 { [Key in keyof T]: ToPrimitive<T[Key]>}
  3. 非对象类型的处理(基本类型和包装对象类型):T extends { valueOf: () => infer P } ? P : T
    • 如果 T 是一个包装对象类型,如 Number 或 String 类型,它会具有一个 valueOf 方法返回对应的原始类型。这里,我们通过条件类型 T extends { valueOf: () => infer P } ? P : T 判断 T 是否具有 valueOf 方法,如果有则返回它的返回值的类型 P。
    • 如果 T 已经是一个原始类型,这个条件类型直接返回原始类型 T。
type ToPrimitive<T> = T extends object ? (
  T extends (...args: never[]) => unknown ? Function : {
    [Key in keyof T]: ToPrimitive<T[Key]>
  }
) : T extends { valueOf: () => infer P } 
    ? P 
    : T;

Solution by linjunc #28263

type Primitives = [string, number, bigint, boolean, symbol, null, undefined];
type GetPrimitive<T, P = Primitives> = P extends [infer F, ...infer R]
  ? T extends F
    ? F
    : GetPrimitive<T, R>
  : never;
type ToPrimitive<T> = T extends object
  ? T extends (...arg: unknown[]) => unknown
    ? Function
    : { [P in keyof T]: ToPrimitive<T[P]> }
  : GetPrimitive<T>;

👍🏻

Solution by DoGukKim #28205

type ToPrimitive<T> = T extends object
  ? {
      [Key in keyof T]: ToPrimitive<T[Key]>;
    }
  : T extends { valueOf: () => infer R }
  ? R
  : T;

Solution by ryuji-1to #27689

type ToPrimitive<T> = {
  [K in keyof T]: T[K] extends string
    ? string
    : T[K] extends number
    ? number
    : T[K] extends boolean
    ? boolean
    : T[K] extends object
    ? ToPrimitive<T[K]>
    : T[K];
} & {};

Solution by ryuji-1to #27688

type ToPrimitive<T> =
  T extends (...args: unknown []) => unknown ? Function :
  T extends object ? { [K in keyof T]: ToPrimitive<T[K]> } :
  T extends { valueOf(): infer P } ? P : T

Solution by smileboyi #27270


type isType<T> = T extends number ? number: T extends string ? string : T extends boolean ? boolean : never
type ToPrimitive<T> = {[K in keyof T]:T[K] extends Function ? Function : T[K] extends Record<PropertyKey,any> ? ToPrimitive<T[K]> : isType<T[K]>}

Solution by WangZiChu199910252255 #26936

// your answers
type ToPrimitive<T> = T extends Function
    ? Function
    : T extends object
    ? {
          [K in keyof T]: ToPrimitive<T[K]>
      }
    : T extends boolean
    ? boolean
    : T extends string
    ? string
    : T extends number
    ? number
    : never;

Solution by studymachiney #24743

type Primitive<T> =
  T extends number ? number :
  T extends string ? string :
  T extends boolean ? boolean :
  T;

type ToPrimitive<T> =
  { [P in keyof T]: T[P] extends Function ? Function :
    T[P] extends object ? ToPrimitive<T[P]> : Primitive<T[P]> };

// old way
// type PrimitiveTypes = {
//   1: string,
//   2: number,
//   3: boolean
// };
// /**利用结构体遍历类型查找 */
// type Primitivation<T> = { [P in keyof PrimitiveTypes as T extends PrimitiveTypes[P] ? P : never]: PrimitiveTypes[P] } extends { [x: number]: infer R } ? R : never;

// type ToPrimitive<T> = T extends Array<any> ?
//   (T extends [infer F, ...infer R] ? [ToPrimitive<F>, ...ToPrimitive<R>] : []) :    //数组
//   (T extends Function ? Function :                                                  //函数
//     (T extends { [x: PropertyKey]: any } ? { [P in keyof T]: ToPrimitive<T[P]> } :  //结构体
//       Primitivation<T>)                                                             //原子类型
//   );

Solution by E-uler #24555

type ToPrimitive<T extends Record<string, unknown> | unknown[]> = {
  [Key in keyof T]: T[Key] extends Record<string, unknown> | unknown[]
    ? ToPrimitive<T[Key]>
    : T[Key] extends string 
      ? string
      : T[Key] extends number 
        ? number
        : T[Key] extends boolean 
          ? boolean
          : never
}

Solution by NeylonR #24373

type toPimitive<T> = {
 [P in keyOf T]: T[P] extends string
 ? string
 : T[P] extends number
  ? number
  : T[P] extends boolean
    ? boolean
    : toPrimitive<T[P]>
}

Solution by Coloey #24210

type Primitives = [string, number, boolean];
type GetPrimitive<T, P = Primitives> = P extends [infer F, ...infer R]
  ? T extends F
    ? F
    : GetPrimitive<T, R>
  : never;

type ToPrimitive<T> = {
  [K in keyof T]: T[K] extends object ? ToPrimitive<T[K]> : GetPrimitive<T[K]>;
};

Solution by nia3y #23373

// your answers
type Primitive<X> = X extends string ? string : X extends number ? number : X extends boolean ? boolean : never

type ToPrimitive<X> = {
  [K in keyof X]: X[K] extends object ? ToPrimitive<X[K]> : Primitive<X[K]>
} 

Solution by snakeUni #23332

// 你的答案
type ToPrimitive<T> = {
    [P in keyof T]: T[P] extends string ? string :T[P] extends number ? number : T[P] extends boolean ? boolean: T[P] extends Record<string,unknown> | unknown[] ? ToPrimitive<T[P]>:never
}

Solution by edisonLzy #22932

// 你的答案
type ToPrimitive<T> = {
  [K in keyof T]: T[K] extends object ? ToPrimitive<T[K]> : T[K] extends { valueOf(): infer R } ? R : T
}

Solution by jxhhdx #22757

type ToPrimitive<T> = T extends object ? {
  [K in keyof T]: ToPrimitive<T[K]>
} : T extends { valueOf(): infer R } ? R : T

Playground

Solution by teamchong #22535

type ToPrimitive<T> =
  T extends string
    ? string
    : T extends number
      ? number
      : T extends bigint
        ? bigint
        : T extends boolean
          ? boolean
          : T extends null
            ? null
            : T extends undefined
              ? undefined
              : T extends [infer A, ...infer Rest]
                ? [ToPrimitive<A>, ...ToPrimitive<Rest>]
                : T extends Record<string, unknown>
                  ? {
                    [Key in keyof T]: ToPrimitive<T[Key]>
                  }
                  : T

Solution by drylint #22129

type ToPrimitive<T> = T extends object ? (
  T extends (...args: never[]) => unknown ? Function : {
    [Key in keyof T]: ToPrimitive<T[Key]>
  }
) : (
  T extends { valueOf: () => infer P } ? P : T
)

Previous implementation (doesn't work with functions):

type ToPrimitive<T> = T extends object ? {
  [Key in keyof T]: ToPrimitive<T[Key]>
} : (
  T extends { valueOf: () => infer P } ? P : T
)

Solution by BOCbMOU #22057

type ToNumber = T extends number ? number : never

type ToString = T extends string ? string : never type ToBoolean = T extends boolean ? boolean : never

type TypeOf = T extends Record<string, any> ? {[K in keyof T]: TypeOf<T[K]>} : ToNumber | ToString | ToBoolean

type PersonInfo = { name: 'Tom', age: 30, married: false, addr: { home: '123456', phone: '13111111111' } }

type test = TypeOf

// 你的答案
  type ToNumber<T> = T extends number ? number : never
  type ToString<T> = T extends string ? string : never
  type ToBoolean<T> = T extends boolean ? boolean : never


  type TypeOf<T> = T extends Record<string, any> ? {[K in keyof T]: TypeOf<T[K]>} : ToNumber<T> | ToString<T> | ToBoolean<T>

  type PersonInfo = { name: 'Tom', age: 30, married: false, addr: { home: '123456', phone: '13111111111' } }

  type test = TypeOf<PersonInfo>

Solution by 437204933 #21946

// 你的答案
  type ToNumber<T> = T extends number ? number : never
  type ToString<T> = T extends string ? string : never
  type ToBoolean<T> = T extends boolean ? boolean : never


  type TypeOf<T> = T extends Record<string, any> ? {[K in keyof T]: TypeOf<T[K]>} : ToNumber<T> | ToString<T> | ToBoolean<T>

  type PersonInfo = { name: 'Tom', age: 30, married: false, addr: { home: '123456', phone: '13111111111' } }

  type test = TypeOf<PersonInfo>

Solution by 437204933 #21936

// 你的答案
  type ToNumber<T> = T extends number ? number : T
  type ToString<T> = T extends string ? string : T
  type ToBoolean<T> = T extends boolean ? boolean : T

  type ToBase<T extends Record<string, any>> = {
    [K in keyof T]: T[K] extends Record<string, any> ? ToBase<T[K]>: ToNumber<ToString<ToBoolean<T[K]>>>
  }

Solution by 437204933 #21935

// 你的答案
  type ToNumber<T> = T extends number ? number : T
  type ToString<T> = T extends string ? string : T
  type ToBoolean<T> = T extends boolean ? boolean : T

  type ToBase<T extends Record<string, any>> = {
    [K in keyof T]: T[K] extends Record<string, any> ? ToBase<T[K]>: ToNumber<ToString<ToBoolean<T[K]>>>
  }

Solution by 437204933 #21934