#57Hard

Get Required

Write GetRequired<T>, which drops every optional property from an object type. The filter runs inside the mapped type: as-remapping a key to never erases it.

A mapped type can delete its own keys: remap them to never and they vanish.

RequiredKeys<T> returns a union of key names. GetRequired<T> goes a step further and builds a whole new object type containing only the required fields, which moves the filtering inside the mapped type: keys get rewritten with an as clause, combined with the assignability trick that detects the ? modifier.

For example

[object Object]

Challenge Instructions: Get Required

Hard

Implement the advanced util type GetRequired<T>, which remains all the required fields

For example

[object Object]

View on GitHub: https://tsch.js.org/57

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

Loading...

Detailed Explanation

The solution:

type GetRequired<T> = {
  [K in keyof T as {} extends Pick<T, K> ? never : K]: T[K]
}

One mapped type with a filter built into its key position. Two ideas combine here.

Detecting optionality without checking undefined

You might be tempted to keep keys where undefined doesn't appear in the value type. The second test case rules that out:

type T = { foo: undefined; bar?: undefined }
// GetRequired<T> must be { foo: undefined }

Both values have type undefined; only the ? modifier distinguishes them. The reliable probe is Pick, which extracts a single property with its modifier intact:

// Pick<T, 'foo'> = { foo: undefined }
// Pick<T, 'bar'> = { bar?: undefined }

Then ask whether the empty object is assignable to it:

So {} extends Pick<T, K> is true exactly for optional keys.

Filtering keys with as-remapping

In a mapped type, the as clause rewrites each key before the property is created:

[object Object]

The rule that makes filtering possible: if NewKey evaluates to never, the property is omitted from the result entirely. Our clause maps optional keys to never (dropped) and required keys to themselves (kept):

[object Object]

For { foo: number; bar?: string }, the mapping runs twice:

// K = 'foo': {} extends { foo: number }  → false → key stays 'foo'
// K = 'bar': {} extends { bar?: string } → true  → key becomes never → dropped
// result: { foo: number }

Compare this with the union-returning cousin RequiredKeys<T>, which maps each value to K or never and then indexes. Here the same conditional sits in the key position, so the filtering happens structurally and the values T[K] ride along unchanged.

Why modifiers take care of themselves

A mapped type of the form [K in keyof T as ...]: T[K] is homomorphic: TypeScript copies each property's readonly and ? modifiers from T automatically. You don't need to add or remove anything. The keys that survive the filter are the required ones, and they arrive without a ? because they never had one. (In GetOptional, the mirror-image challenge, this same behavior is what keeps the ? on the surviving keys.)

Edge cases the tests cover

Once this clicks, you have a general recipe: any 'keep the keys where X holds' type is [K in keyof T as Test ? K : never]: T[K] with your predicate plugged in.

This challenge is originally from here.

Share this challenge

Learn the Concepts