00553-hard-deep-object-to-unique

Back

思考一下子两个类型是否可以互相赋值? type A = { a: string } type B = { a: string; b?: string } 答案是可以的,并且A和B是不同的类型。完全符合本题要求。 但是有个问题是,上面的可选属性b是否可以定义一个不会属性污染的,答案是使用 unique symbol

那么思路就出来了,递归遍历所有对象,对每个加上可选的 unique symbol 的属性,但要注意,这个属性对应的值不能完全一样,不然 IsFalse<Equal<UniqBar["baz"], UniqFoo["baz"]>> 通过不了



declare const UniqKey: unique symbol;

type DeepObjectToUniq<T, Count extends any[] = [T]> = {
  [P in keyof T]: T[P] extends Record<PropertyKey, any>
    ? DeepObjectToUniq<T[P], [...Count, P]>
    : T[P];
} & {
  [UniqKey]?: Count;
};

Solution by Vampirelee #32623

type DeepObjectToUniq<O extends object, _UniqFlag extends [PropertyKey?, object?] = []> =
  { [P in keyof O]: O[P] extends object ? DeepObjectToUniq<O[P], [P, O]> : O[P] }
  & { [flag: symbol]: _UniqFlag }   //为结构体打上独特的标志[字段名, 拥有者]

Solution by E-uler #24879

declare const KEY: unique symbol;
type DeepObjectToUniq<T extends object> = {
  [K in keyof T]: T[K] extends object ? DeepObjectToUniq<T[K]> & { readonly [KEY]?: [T, K] } : T[K]
}

Solution by TKBnice #22948

declare const sym: unique symbol;

type DeepObjectToUniq<O extends object> = {
  [K in keyof O]: O[K] extends object
    ? O[K] extends Function
      ? O[K]
      : DeepObjectToUniq<O[K]> & { readonly [sym]?: [O, K] }
    : O[K]
} & {
  readonly [sym]?: unknown
}

Solution by milletlovemouse #21804

declare const KEY: unique symbol;

type DeepObjectToUniq<O extends object> = {
  [K in keyof O]: 
    O[K] extends object
      ? DeepObjectToUniq<O[K]> & {readonly [KEY]?: [O, K]}
      : O[K]
} & {readonly [KEY]?: [O]}

Learned a lot from others:

Keys are:

Solution by zhaoyao91 #20863

type DeepObjectToUniq<O extends object, U extends any[] = []> =
  { [x: symbol]: U}
  &
  {
    [K in keyof O]: O[K] extends object
      ? DeepObjectToUniq<O[K], [O, K]>
      : O[K];
  }

Solution by logan70 #19235

type DeepObjectToUniq<O extends object, U extends any[] = [O]> = {
  [key in keyof O]: O[key] extends object ? DeepObjectToUniq<O[key], [...U, key]> : O[key];
} & { [key in symbol]: U };

& { [key in symbol]: U }; don't understand this code??

Solution by CaoXueLiang #19053

// your answers
type DeepObjectToUniq<O extends object, K extends any[] = []> = {
  [P in (keyof O | symbol)]: P extends keyof O ?  O[P] extends object ? DeepObjectToUniq<O[P], [...K, O, P]> : O[P]
                                               : K
}

Solution by Stan-BK #16492

// your answers

type DeepObjectToUniq<O extends object, U extends readonly any[] = [O]> = {
  [K in keyof O]: O[K] extends object
    ? DeepObjectToUniq<O[K], [...U, K]>
    : O[K]
} & { [K in symbol]: U }

Solution by humandetail #16444

// your answers
type DeepObjectToUniq<
    O extends object,
    U extends readonly any[] = [O]> = 
    {[J in keyof O]: O[J] extends object 
    ? DeepObjectToUniq<O[J],[...U,J]> 
    : O[J]}
    &{[K in symbol]:U}  ;

Solution by justBadProgrammer #15865

type ToUnionOfFunction<T> = T extends any ? (x: T) => any : never;
type UnionToIntersection<U> = ToUnionOfFunction<U> extends (a: infer U) => any ? U : never

type DeepPick<T, S extends string> = UnionToIntersection<
  S extends `${infer First extends keyof T & string}.${infer Rest}`
  ? { [K in First]: DeepPick<T[First], Rest> }
  : S extends keyof T
  ? { [K in S]: T[S] }
  : never
>

Solution by liuxing95 #12748

// your answers
type DeepObjectToUniq<O extends object> = {
  [K in keyof O]: O[K] extends object
    ? DeepObjectToUniq<O[K] & { _?: [O, K] }>
    : O[K];
};


Solution by SeptEarlyMorning #11909

type DeepObjectToUniq<O extends object,
  Path extends Array<keyof any | object> = [O],
  UniqueO = O & { readonly [Tag]?: Path }> =
  {
    [K in keyof UniqueO]: UniqueO[K] extends object ? (
      DeepObjectToUniq<UniqueO[K], [...Path, K]>
    ) : UniqueO[K]
  }

declare const Tag: unique symbol

Declare a unique symbol instead of using { [S in symbol]: Path } Playground

Solution by teamchong #11436

// your answers

// the main idea is to add a unique {symbol: Path} to each property
type DeepObjectToUniq<O extends object, Path extends Array<unknown> = [O]> = O extends Record<keyof any, any> ? {
  [K in keyof O]: DeepObjectToUniq<O[K], [...Path, K]>
} & {
  [K in symbol] : Path
} : O;

Solution by Joyee691 #11416

TypeScript PlayGround

const symbol = Symbol()
type DeepObjectToUniq<O extends object, Path extends any[] = [O]> = {
  [K in keyof O]: O[K] extends object ? DeepObjectToUniq<O[K], [...Path, K]> : O[K]
} & { [symbol]?: Path }

Solution by Lionad-Morotar #9103

type DeepObjectToUniq<O extends object, Path extends any[] = [O]> = O extends Record<string,any> ? {
  [key in keyof O]: DeepObjectToUniq<O[key],[...Path,key]>  
} & {
  [key in symbol]: Path
}: O

Solution by EGyoung #8637

// 553 - Deep object to unique type Merge = { [P in keyof T]: T[P] } type DeepObjectToUniq = { [P in keyof T]: T[P] extends object ? DeepObjectToUniq<Merge<T[P] & { _?: [T, P]}>> : T[P] }

Solution by Carefree-happy #7040

type Merge<T> = {
  [P in keyof T]: T[P]
}
type DeepObjectToUniq<O extends object> = {
  [P in keyof O]: O[P] extends object
    ? DeepObjectToUniq<Merge<O[P] & { _xxx?: [O, P] }>>
    : O[P]
}

Solution by myNameIsDu #2832

// your answers
type DeepObjectToUniq<O extends object> = {
  [k in keyof O]: O[k] extends object ? DeepObjectToUniq<O[k]> & { _uniq?: [O, k] } : O[k]
}

Solution by zongzi531 #2035

// your answers
type DeepObjectToUniq<O extends object> = {
  [k in keyof O]: O[k] extends object ? DeepObjectToUniq<O[k]> & { _uniq?: [O, k] } : O[k]
}

Solution by emandirola #1163

TS Playground.

type Key = string | number | symbol;

declare const KEY: unique symbol;

type DeepObjectToUniq<
  O extends object,
  Parent = O,
  Path extends readonly Key[] = []
> = {
  [K in keyof O]: O[K] extends object
    ? DeepObjectToUniq<O[K], O, [...Path, K]>
    : O[K];
} & {
  readonly [KEY]?: readonly [Parent, Path];
};

Solution by uid11 #581