00005-extreme-readonly-keys

Back

// 1.	[P in keyof T]-?: 遍历类型 T 的所有属性键,-? 确保包括可选属性。
// 2.	Equal<{ [K in P]: T[P] }, { -readonly [K in P]: T[P] }>: 判断属性 P 是否为只读,通过比较移除 readonly 之前和之后的属性类型。
// 3.	如果 Equal 返回 true,表示该属性不是只读属性,我们用 never 过滤掉;否则返回属性键 P。
// 4.	最后通过索引访问 [keyof T] 构造出一个联合类型,提取所有只读属性的键。

type GetReadonlyKeys<T> = {
  [K in keyof T]-?: Equal<{ [R in K]: T[K] }, { -readonly [R in K]: T[K] }> extends true ? never : K;
}[keyof T];

Solution by zqy1151215064 #34725

// 将T转换为必填对象,遍历键与未转换之前对比,如果去掉readonly的键与未转换之前的不相等则丢弃,否则保留
type GetReadonlyKeys<T> = {
  [Keys in keyof Required<T>]: Equal<{
    [K in Keys]: T[K] }, {
      -readonly [P in Keys]: T[Keys]
    }
  > extends true ? never : Keys }[keyof T]

Solution by ouzexi #34442

  1. 首先遍历T的所有属性
  2. 判断单条属性是否是只读属性, 通过Equal<{ [k in P]: T[k]}, { -readonly [R in P]: T[R] },如果为true,表示为非只读属性,则过滤掉,如果为false,代表只读属性,添加到映射的对象中
  3. 对过滤后的对象取 keyof
type GetReadonlyKeys<T> = keyof { 
  [P in keyof T as Equal<{ [k in P]: T[k]}, { -readonly [R in P]: T[R] }> extends true ? never: P]: T[P]
}

Solution by chenghao125 #33298

// your answers
type IsEqual<S,U> = (<T>() => T extends S ? 1 : 2) extends (<T>() => T extends U ? 1 : 2)  ?  true : false  
type Writable<T> = T extends object ? { -readonly [key in keyof T]:T[key] } :T ;
type getProperty<T extends object,K extends keyof T> = {
  [v in  K]:T[v]
} 
type GetReadonlyKeys<T extends object> =  keyof ({
  [key in keyof T as IsEqual<getProperty<T,key>,getProperty<Writable<T>,key>> extends true ? never:key ]:true
})

Solution by sciencefunq #32914

type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false

type GetReadonlyKeys<
  T extends Record<keyof T, unknown>,
  U extends Record<keyof T, unknown> = Readonly<T>,
  K extends keyof T = keyof T
> = K extends keyof T
  ? Equal<Pick<T, K>, Pick<U, K>> extends true ? Pick<T, K> : never
  : never

interface Todo {
  readonly title: string
  readonly description: string
  completed: boolean
}

type Keys = GetReadonlyKeys<Todo> // expected to be "title" | "description"

const test: Keys = {
  title: 'T123',
  description: 'D123'
}

Solution by ZhulinskiiDanil #32721

type MyEqual<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y
  ? 1
  : 2
  ? true
  : false;
  
type GetReadonlyKeys<T, K extends keyof T = keyof T> = K extends any
  ? MyEqual<Pick<T, K>, Mutable<Pick<T, K>>> extends true
    ? never
    : K
  : never;

type Mutable<T> = {
  -readonly [P in keyof T]: T[P];
};

Solution by Vampirelee #32717

type GetReadonlyKeys<T, R extends keyof T = keyof T> = R extends unknown
  ? Equal<
      { [K in keyof T as K extends R ? K : never]: T[K] },
      { readonly [K in R]: T[K] }
    > extends true
    ? R
    : never
  : never;

Solution by vangie #32341

type GetReadonlyObject<T> = {
  [Properties in keyof T as Equal<Pick<T, Properties>, Readonly<Pick<T, Properties>>> extends true ? Properties : never]: T[Properties]
}

type GetReadonlyKeys<T> = keyof GetReadonlyObject<T>

Solution by trinhvinhtruong96 #32024

// 你的答案
type GetReadonlyKeys<T extends object> = keyof {
  [K in keyof T as Equal<Readonly<{
    [P in K]: T[P]
  }>, {
    [P in K]: T[P]
  }> extends true ? K : never]: T[K]
}

Solution by TRIS-H #31191

type AllKeys<T> = keyof T;
type GetReadonlyKeys<T> = keyof {
  [k in AllKeys<T> as Equal<Pick<T, k>, Readonly<Pick<T, k>>> extends true ? k : never]: true
}

Solution by denysoblohin-okta #30429

// your answers
type equal<X, Y> = (<T>() => T extends X ? 1 : 2 ) extends <T>() => T extends Y ? 1 : 2 ? true : false
type GetReadonlyKeys<T> =  { [K in keyof T]: equal<{ readonly [P in K]: T[K] }, { [P in K]: T[K] }> extends true ? K : never }[keyof T]

Solution by xiezhenghua123 #29990

interface Todo {
  readonly title: string
  readonly description: string
  readonly abc: string
  completed: boolean
}

type GetReadonlyKeys<T> =  keyof {[K in keyof T as K extends Readonly<T[K]> ? K : never]: T[K]}

type Keys = GetReadonlyKeys<Todo> // expected to be "title" | "description"

Solution by yufengctbu #29987

// 你的答案
type GetReadonlyKeys<T> = keyof {[k in keyof T as Equal<Pick<T,k> , Readonly<Pick<T,k>>> extends true ? k : never]:k}

Solution by WangZiChu199910252255 #29674


type Equal<X, Y> = (<T>()=> T extends X ? 1: 2) extends (<T>()=> T extends Y ? 1: 2) ? true : false
type getReadOnlyKeys<T, U  extends Readonly<T> = Readonly<T>, K extends keyof T = keyof T> = K extends keyof T ? Equal<Pick<T, K>,Pick<U,K>> extends true ? K: never : never

Solution by Zeoy9728 #29631

type GetReadonlyKeys<T> = {
	[K in keyof T]-?: Equal<Pick<T, K>, Readonly<Pick<T, K>>> extends true
		? K
		: never;
}[keyof T];

Solution by blazeshomida #29473

// your answers
type ReadonlyKeyAlias<T, PK extends keyof T> = Equal<Pick<T, PK>, Readonly<Pick<T, PK>>> extends true ? PK : never
type GetReadonly<T> = {
  [PK in keyof T as ReadonlyKeyAlias<T, PK>]: T[PK]
}
type GetReadonlyKeys<T> = keyof GetReadonly<T>

Solution by trinhvinhtruong96 #28756

type GetReadonlyKeys<T> = keyof {
  [K in keyof T as Equal<Pick<T, K>, Readonly<Record<K, T[K]>>> extends true
    ? K
    : never]: T[K];
};

Solution by JohnLi1999 #26363

// 你的答案

// 就是逐个字段取出来 比较一下 如果是readonly,就标记为null或其他 最后把这个字段key取出来

// 这里「借用」了@type-challenges/utils的 Equal
type Eq<X, Y> =
  (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? true : false

// 取反
type Not<T extends boolean> = T extends true ? false : true;

type getField<T, K extends keyof T> = Pick<T, K>
type delReadonly<T, K extends keyof T> = {
  -readonly [k in K]: T[k]
}

type getFields<T> = {
  [Propertie in keyof T]: fieldIsReadOnly<T, Propertie>
}

type fieldIsReadOnly<T, K extends keyof T> = Not<Eq<getField<T, K>, delReadonly<T, K>>>

type falseToNever<T> = {
  [Propertie in keyof T]: T[Propertie] extends true ? true : Propertie;
}

type removeNeverField<T> = {
  [Propertie in keyof T as T[Propertie] extends Propertie ? never : Propertie ]: T[Propertie]
}

type GetReadonlyKeys<T> = keyof removeNeverField<falseToNever<Required<getFields<T>>>>

Solution by alexsunday #26188

type GetReadonlyKeys<T extends object> = keyof { [P in keyof T  as Equal<{ [K in P]: T[P] }, { readonly [K in P]: T[P] }> extends true ? P : never]: T[P] };

Solution by E-uler #25425

type MyEqual<A, B> = (<X>() => X extends A ? 0 : 1) extends <X>() => X extends B
  ? 0
  : 1
  ? true
  : false;

type isReadonly<T, K extends keyof T> = MyEqual<
  { [P in K]: T[P] },
  { readonly [P in K]: T[P] }
>;

type GetReadonlyKeys<T> = keyof {
  [K in keyof T as isReadonly<T, K> extends true ? K : never]: T[K];
};

Solution by Creo-KR #25201

// your answers
type GetReadonlyKeys<T> = keyof {
  [Key in keyof T as Equal<{ [K in Key]: T[Key] }, { -readonly [K in Key]: T[Key] }> extends false
    ? Key
    : never
  ]: T[Key]
}

Solution by snakeUni #24351

type GetReadonlyKeys<T> = keyof {[Key in keyof T as Equal<Pick<T, Key>, Readonly<Pick<T, Key>>> extends true ? Key : never]: Key}

Solution by sabercc #23397

type GetReadonlyKeys<T> = keyof {
  [Key in keyof T as Equal<{ [K in Key]: T[Key] }, { -readonly [K in Key]: T[Key] }> extends false
    ? Key
    : never
  ]: T[Key]
}

Solution by drylint #23301

// 你的答案
type IsEqual<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false

type GetReadonlyKeys<T> = keyof {
  [K in keyof T as IsEqual<Pick<T, K>, Readonly<Pick<T, K>>> extends true ? K : never]: T[K]
}

Solution by jxhhdx #23012

// Pick: only returns P that are in K (returns object = key, value pair)
type MyPick<T, K extends keyof T> = { [P in K]: T[P] };
// Readonly: force element's type as readonly => grants immutability within TS
type MyReadonly<T> = { readonly [P in keyof T]: T[P] };
// Equal:
// prettier-ignore
type IsEqual<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B
  ? 1
  : 2)
  ? true
  : false;
// IsReadonly: compare K's type and forced K's type as readonly
type IsReadonly<T, K extends keyof T> = IsEqual<
  MyPick<T, K>,
  MyReadonly<MyPick<T, K>>
>;
// if K is keyof T and readonly return K or never
type GetReadonlyKeys<T, K = keyof T> = K extends keyof T
  ? IsReadonly<T, K> extends true
    ? K
    : never
  : never;

Solution by brandonwie-moviation #22423

type IsEqual<A, B> = 
  (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2)
  ? true 
  : false

type IsReadonlyKey<O, K extends keyof O, _OPK = Pick<O, K>> = IsEqual<_OPK, Readonly<_OPK>>

type GetReadonlyKeys<T, K extends keyof T = keyof T> = 
  K extends unknown
  ? IsReadonlyKey<T, K> extends true ? K : never
  : never

playground

Well, this is just a subset of Mutable Keys(Solution of Mutable Keys)

Solution by zhaoyao91 #22098

// 你的答案
type GetReadonlyKeys<T, K extends keyof T = keyof T>
    = K extends K
    ? Equal<{ [P in K]: T[K] }, { readonly [P in K]: T[K] }> extends true
    ? K : never : never

Solution by goddnsgit #22066

type IsReadOnly<T, P extends keyof T> = Equal<Pick<T, P>, {readonly [K in P]: T[P]}>

type GetReadonlyKeys<T> =  keyof {
  [P in keyof T as IsReadOnly<T, P> extends true ? P: never]: T[P]
}

Solution by sromic #21522

type UnionToIntersection<U> = (
  U extends U ? (x: U) => unknown : never
) extends (x: infer R) => unknown
  ? R
  : never;
  
type GetReadonlyKeys<
  T extends Record<string, any>,
  G extends keyof T = keyof T
> = keyof UnionToIntersection<
  G extends G
    ? Equal<Pick<T, G>, Readonly<Pick<T, G>>> extends true
      ? Pick<T, G>
      : never
    : never
>;

Solution by so11y #21382

type ShouldReadonly<TObj, TKey extends keyof TObj> = Equal<Pick<TObj, TKey>, Readonly<Pick<TObj, TKey>>> extends true ? TKey : never;

type GetReadonlyKeys<T> = keyof {
  [TKey in keyof T as ShouldReadonly<T, TKey>]: T[TKey]
}

Solution by mdakram28 #20641