#34857Medium

Defined Partial Record

### Defined Partial Record Master advanced TypeScript type manipulation in this medium-level challenge on TypeScriptPro.

In this medium-level challenge, you'll implement DefinedPartial<T> which creates a union of all non-empty subsets of an object type, so that present keys have defined (non-undefined) values and absent keys simply do not exist on the type.

Challenge Instructions: Defined Partial Record

Medium

Defined Partial Record

Using a Record with union types as keys doesn't allow you to make an object with only some of them

const record: Record<'a' | 'b' | 'c', number> = { a: 42, b: 10 }
// error: Property 'c' is missing in type '{ a: number; b: number; }'
// but required in type 'Record<"a" | "b" | "c", number>'

Using a Partial Record with union types as keys allows you to make an object without all union members, but makes all keys and values optional, potentially leaving them undefined

const partial: Partial<Record<'a' | 'b' | 'c', number>> = { a: 42 }
const partialType = typeof partial // { a?: number | undefined, b? : number | undefined, c? : number | undefined }
const operation = 0 + partial.a // error: 'partial.a' is possibly 'undefined'
const access = partial.c // possible, type doesn't know that there is no such key

You need to make a type that takes the best of both worlds, creates all combinations of all the types in the union, so using a key that exists in the object gives you a defined type, but using a key that exists in the union and not in the object throws an error

const best: DefinedPartial<Record<'a' | 'b' | 'c', number>> = { a: 42 }
const sum = 0 + best.a // 42
const error = best.b // error: property 'b' does not exist on type '{ a: number; }'

Change the following code to make the test cases pass (no type check errors).

Loading...

Detailed Explanation

type DefinedPartial<T, K extends keyof T = keyof T> =
  [K] extends [never]
    ? never
    : K extends keyof T
      ? { [P in K]: T[P] } | DefinedPartial<T, Exclude<keyof T, K>>
        | { [P in K]: T[P] } & DefinedPartial<T, Exclude<keyof T, K>> extends infer U
          ? U extends object ? { [P in keyof U]: U[P] } : never
          : never
      : never

A cleaner recursive approach that generates the powerset of keys:

type Powerset<K extends PropertyKey> = K extends K
  ? { [P in K]: unknown } | (Powerset<Exclude<K, K>> extends never ? never : never)
  : never
 
type DefinedPartial<T, K extends keyof T = keyof T> =
  K extends keyof T
    ? Pick<T, K> | Merge<Pick<T, K> & DefinedPartial<T, Exclude<keyof T, K>>>
    : never
 
type Merge<T> = { [K in keyof T]: T[K] }

The most straightforward correct solution distributes over each key and builds up combinations:

type DefinedPartial<T, K extends keyof T = keyof T> =
  K extends keyof T
    ? Pick<T, K> | (
        DefinedPartial<T, Exclude<keyof T, K>> extends infer Rest
          ? Rest extends any
            ? { [P in keyof (Pick<T, K> & Rest)]: (Pick<T, K> & Rest)[P] }
            : never
          : never
      )
    : never

How it works:

This challenge helps you understand powerset generation at the type level using distributive conditional types and how to apply this concept in real-world scenarios.

This challenge is originally from here.

Share this challenge

Learn the Concepts

Join early, learn faster.

Be the first to access the course, unlock exclusive launch bonuses, and get special early-bird pricing before anyone else.

No spam, unsubscribe at any time. We respect your privacy.

Limited Availability

Only 27 Spots left

Early Access

Get 1 month early access

>75% Off

Pre-Launch discount