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'> // falseImplement 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'> // falseView 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.
The entire solution is one comparison:
type IsRequiredKey<T, K extends keyof T> =
Pick<T, K> extends Required<Pick<T, K>> ? true : falseOne line, leaning on a subtle property of how TypeScript models optionality.
undefinedYour 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.
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.
Required trickRequired<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.
IsRequiredKey<{ a: undefined; b: string }, 'a'> β true: Required<{ a: undefined }> is still { a: undefined }; on a property that was never optional, Required changes nothing, so the check passes.IsRequiredKey<{ a: undefined; b: undefined }, 'b' | 'a'> β true: both properties are required despite being typed undefined; picking both and requiring both changes nothing.IsRequiredKey<{ a: number; b?: string }, 'b' | 'a'> β false: one optional key in the union poisons the whole check, because the comparison happens on the combined object, not per key.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.