02946-medium-objectentries

Back

type ObjectEntries<T, U = Required<T>> = {
  [K in keyof U]: [K, U[K] extends never ? undefined : U[K]]
}[keyof U]

Solution by devshinthant #34934

type ObjectEntries<T, U = Required<T>> = {
  [P in keyof U]-?: [P, U[P] extends never ? undefined : U[P]]
}[keyof U]

Solution by 2083335157 #34886

// 数组转联合类型用 [number] 作为下标 ['1', '2']['number']  --->  '1' | '2'
// 对象转联合类型用 [keyof T] 作为下标 {a: 1, b: 2}[keyof T] --->  1 | 2

// 如果key是可选的,则Required将删除value的undefined类型。
// { a?: undefined } => { a: never }
// { a?: string | undefined } => { a: string }
type ObjectEntries<T> = {
  [K in keyof T]-?: [K, [Required<T>[K]] extends [never] ? undefined : Required<T>[K]]
}[keyof T]

Solution by ouzexi #34053

// your answers
type ObjectEntries<T> = { [key in keyof T]-?: [key, Required<T>[key] extends never ? undefined : Required<T>[key]] }[keyof T];

Solution by pea-sys #32930

type ObjectEntries<T extends object> = 
  { [K in keyof T]-?: [K, Required<T>[K] extends never ? undefined : Required<T>[K]] }[keyof T]

Required 유틸리티 타입은 key가 옵셔널이면 value의 undefined 타입을 제거한다.

  1. { a?: undefined } => { a: never }
  2. { a?: string | undefined } => { a: string }

Solution by dev-hobin #32522

type ObjectEntries<T, U= Required<T>> = {
  [K in keyof U]-?: [K, U[K] extends never ? undefined : U[K]] 
}[keyof U]

Solution by maximallain #32232

// your answers

type RequireObj<T> = {
  [P in keyof T]-?: T[P]
}
type _ObjectEntries<T, U extends keyof T> = U extends U ? [U, [T[U]] extends [undefined] ? undefined : T[U]] : never;
type ObjectEntries<T> = _ObjectEntries<RequireObj<T>, keyof T>;

Solution by tarotlwei #31707

type ObjectEntries<T> = Entries<Required<T>>;

type Entries<T> = {
    [P in keyof T]: [P, [T[P]] extends [never] ? undefined : T[P]]
}[keyof T];

Solution by sdrjs #31543

type TransformValue<T> = {
	[k in keyof T]: [k, T[k]];
}[keyof T];
type ObjectEntries<T, U extends keyof T = keyof T> = U extends any
	? TransformValue<
		Equal<{ [k in U]: T[k] }, { [k in U]?: undefined }> extends true
			? { [k in U]-?: undefined }
			: { [k in U]-?: T[k] }
	  >
	: never;

Solution by TRIS-H #31505

Minimal Approach

type ObjectEntries<T> = {
  [Prop in keyof T as number]: [Prop, T[Prop] extends undefined ? undefined : Required<T>[Prop]]
} [0]

Solution by fredski02 #31278

type ObjectEntries<T, U = Required<T>> = {
  [key in keyof U]: [key, U[key] extends never ? undefined : U[key]];
}[keyof U];

Solution by leejaehyup #30793

The type system implicitly adds | undefined to the type of optional properties. If we remove the optional specifiers (by using R = Required<T>) before we build the entry pairs, we avoid these implicitly added undefined for both the entry values and the union of entries:

type ObjectEntries<T, R = Required<T>> = {
  [K in keyof R]: [K, R[K]]
}[keyof R]

At first sight, this solution causes the following check to fail:

  Expect<Equal<ObjectEntries<{ key?: undefined }>, ['key', undefined]>>,

The intention of this check seems to be that an explicit undefined in the type of an optional property should not be removed.

Just quieting the test down by addressing this particular case in the code of the solution is not appropriate as it does not generally keep an explicit undefined in the type of a property. Instead we should even add one more test case:

  Expect<Equal<ObjectEntries<{ key?: string | undefined }>, ['key', string | undefined]>>,

With this additional check, it is even no longer possible to get all checks pass by changing the code of the solution: We have here an explicit type string | undefined for the optional key property, whereas the check for Partial<Model> implicitly changes the type of the name property to string | undefined by making it optional. As the type system does not distinguish between an explicit or implicitly added undefined for optional properties, the problem cannot be solved by changing the code.

Nor it should. As the problem is in the type system, it should be solved there. This can be done by setting the tsConfig flag

“exactOptionalPropertyTypes”: true

When set, the type system now remembers whether undefined has implicitly been added for an optional property (in order to prevent assignment of an undefined value), and Required<T> no longer removes an explicit undefined. The solution then passes all checks (including the additional check mentioned above).

Solution by sbr61 #30113

// your answers
type ObjectEntries<T> = { [key in keyof T]-?: [key, Required<T>[key] extends never ? undefined : Required<T>[key]] }[keyof T];

Solution by WeiRu1016 #29979

type Remove<T> = [T] extends [infer A | undefined] ? A : T
type ObjectEntries<T, U extends keyof T = keyof T> = {
    [P in U]-?: [P, Partial<T> extends T ? Remove<T[P]> : T[P]]
}[U]

Solution by hesoso #29788

type RemoveUndefined<T> = [T] extends [undefined] ? T : Exclude<T, undefined>
type ObjectEntries<T, K = keyof T> =
  K extends keyof T
  ? [K, T[K] extends Required<T>[K] ? T[K] : RemoveUndefined<T[K]>]
  : never

This code passes all test cases.

Solution by tyama711 #29744

type ObjectEntries<T, U = keyof T> = U extends keyof T ? [U, T[U]] : never

Solution by alkkas #29341

type ObjectEntries<T, K extends keyof T = keyof T> = K extends keyof T
  ? [K, T[K] extends undefined ? T[K] : Exclude<T[K], undefined>]
  : never;

Solution by DoGukKim #29199

type ObjectEntries=keyof T extends infer A?A extends keyof T?[A,T[A]]:never:never interface Model { name: string|number; age: number; locations: string[] | null; }

Solution by sunhk123456 #28955

type RemoveUndefined<T> = [T] extends [undefined] ? T : Exclude<T, undefined>

type ObjectEntries<T> = RemoveUndefined<{
  [K in keyof T]: {} extends Pick<T, K> ? [K, RemoveUndefined<T[K]>] : [K, T[K]]
}[keyof T]>

Solution by DoubleWoodLin #28697

type ObjectEntries<T, K = { [P in keyof T]-?: T[P] }> = keyof K extends infer U
  ? U extends U
    ? [U, K[U & keyof K] extends never ? undefined : K[U & keyof K]]
    : never
  : never;

Solution by DoGukKim #28167

type ObjectEntries<T extends { [key: string]: any }> = Partial<{
  [Key in keyof T]: [Key, Required<T>[Key]];
}> extends { [key: string]: infer V }
  ? V extends [infer F, infer R]
    ? [F, [R] extends [never] ? undefined : R]
    : never
  : never;

Solution by idebbarh #28163

Main idea: If the key type is optional, the value type needs to erase the undefined type. The specific code is as follows.

/**
 * Get the optional type, principle: change a key to optional, and if it still extends the original type, it proves to be optional.
 * reference:https://zhuanlan.zhihu.com/p/43206436
 */
type IsOptional<T, K extends keyof T> = {
  [K1 in Exclude<keyof T, K>]: T[K1]
} & { K?: T[K] } extends T ? true : false

type RemoveUndefined<T> = [T] extends [undefined] ? T : Exclude<T, undefined>

type ObjectEntries<T> = {
  [K in keyof T]-?: [K, IsOptional<T, K> extends true ? RemoveUndefined<T[K]> : T[K]]
}[keyof T]

Solution by NameWjp #28036

// your answers
type ObjectEntries<T, K extends keyof T = keyof T> = K extends unknown ? [K, T[K] extends undefined?T[K]:Required<T>[K]] : never

Solution by AAA611 #27877

// your answers
type ObjectEntries<T, U = Required<T>> = {
  [K in keyof U]: [K, U[K] extends never ? undefined : U[K]]
}[keyof U]

Solution by daiki-skm #27849

// your answers
type RemoveUndefined<T> = [T] extends [undefined] ? T : Exclude<T, undefined>
type ObjectEntries<T> = {[K in keyof T] -?: [K, RemoveUndefined<T[K]>]}[keyof T]

Solution by GreattitJY #27683

type RemoveUndefined<T> = [T] extends [undefined] ? T : Exclude<T, undefined> 

type ObjectEntries<T, _U extends keyof T = keyof T> = 
  _U extends _U ? [_U, RemoveUndefined<T[_U]>] : never;

Solution by jjswifty #27630

type UnPartial<T> = Omit<{
  [P in keyof T as T[P] extends undefined ? never : P]-? : T[P]
} & {
  [P in keyof T as T[P] extends undefined ? P : never] : T[P]
}, never>

type ObjectEntries<T, U = UnPartial<T>> = keyof U extends infer P ?
  P extends keyof U ? [P, U[P]] : never : never

Solution by 8471919 #27559

type ObjectEntries<T, K extends keyof T = keyof T> = [keyof T] extends [never]
  ? []
  : K extends K
    ? [
        K, Exclude<T[K], undefined> extends infer R
          ? [R] extends [never]
              ? undefined
              : R
          : never,
      ]
    : []

Solution by jazelly #27395

// your answers

type RemoveUndefined<T> = [T] extends [undefined] ? undefined : T extends undefined ? never : T

type ObjectEntries<T, K extends keyof T = keyof T> = K extends any ? [K, RemoveUndefined<T[K]>] : never

Solution by 774653363 #27168

type ObjectEntries<T, U = Required<T>> = {
  [K in keyof U]: [K, U[K] extends never ? undefined : U[K]]
}[keyof U]

Solution by isntkyu #27020