#2857β€’Hard

IsRequiredKey

IsRequiredKey<T, K> reports whether every key in K is required on T. Optionality is a modifier, not a value type, so the check compares Pick against Required.

{ a: undefined } and { a?: undefined } are different types, and this challenge is about telling them apart.

IsRequiredKey<T, K> returns true if every key in K is a required property of T, and false otherwise. Because optionality is a modifier on the property rather than part of its value type, checking for undefined gets you nowhere: a property typed a: undefined is still required, while b?: string is optional. The solution plays Required and Pick against each other and lets structural assignability report the difference.

For example

type A = IsRequiredKey<{ a: number, b?: string },'a'> // true
type B = IsRequiredKey<{ a: number, b?: string },'b'> // false
type C = IsRequiredKey<{ a: number, b?: string },'b' | 'a'> // false

Challenge Instructions: IsRequiredKey

Hard

Implement a generic IsRequiredKey<T, K> that return whether K are required keys of T .

For example

type A = IsRequiredKey<{ a: number, b?: string },'a'> // true
type B = IsRequiredKey<{ a: number, b?: string },'b'> // false
type C = IsRequiredKey<{ a: number, b?: string },'b' | 'a'> // false

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

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

πŸ‘‹ Lifetime-License is leaving on August 10, 2026

Get it now for $29

One-time payment. Lifetime access to all pro challenges.

Loading...

Detailed Explanation

The entire solution is one comparison:

type IsRequiredKey<T, K extends keyof T> =
  Pick<T, K> extends Required<Pick<T, K>> ? true : false

One line, leaning on a subtle property of how TypeScript models optionality.

Why you can't just check for undefined

Your first instinct might be: "a key is optional if undefined is part of its type." But look at this test case:

type cases = [
  Expect<Equal<IsRequiredKey<{ a: undefined; b: string }, 'a'>, true>>,
]

Here a is explicitly typed as undefined, yet it's a required key: you must write { a: undefined, b: '...' }, and omitting a is an error. Optionality lives in the ? modifier on the property declaration, not in the value type. So the solution needs a way to interrogate the modifier itself.

Isolating the keys under test

Pick<T, K> builds a new object type containing only the properties named by K, keeping their modifiers intact. For T = { a: number; b?: string }:

// Pick<T, 'a'>       = { a: number }
// Pick<T, 'b'>       = { b?: string }
// Pick<T, 'a' | 'b'> = { a: number; b?: string }

Note that Pick handles the union case for free: when K is 'a' | 'b', we get an object with both properties, so a single check can decide whether all of them are required. There's no distribution happening here (a conditional type only distributes when the checked type is a bare type parameter, and Pick<T, K> is not bare), which is exactly what we want: one optional key should make the whole answer false.

The Required trick

Required<X> is the built-in utility that strips the ? modifier from every property (its implementation is { [P in keyof X]-?: X[P] }; the -? syntax removes the modifier). Now compare the picked type against its fully-required twin:

// Pick<T, 'a'> = { a: number }    Required<...> = { a: number }   β†’ identical
// Pick<T, 'b'> = { b?: string }   Required<...> = { b: string }   β†’ different!

If none of the picked keys were optional, Required changes nothing and Pick<T, K> extends Required<Pick<T, K>> holds, so the answer is true. But if any key was optional, Required tightens it, and the check fails: { b?: string } is not assignable to { b: string }, because a value of the optional type might omit b entirely.

The direction of the check matters. Flipping it to Required<Pick<T, K>> extends Pick<T, K> would always be true, since a required property is always assignable to its optional counterpart. You must ask whether the possibly-optional side satisfies the required side.

Edge cases the tests cover

When you need to reason about ? modifiers in the type system, don't inspect value types. Build two object types that differ only in the modifier and test assignability between them.

This challenge is originally from here.

Share this challenge

Learn the Concepts