Implement a generic `RequiredByKeys<T, K>` which takes two type argument `T` and `K`. Master advanced TypeScript type manipulation in this medium-level challenge on TypeScriptPro.
In this medium-level challenge, you'll implement RequiredByKeys<T, K> which makes only the specified keys of T required while leaving the rest unchanged, defaulting to making all properties required when K is not provided.
Implement a generic RequiredByKeys<T, K> which takes two type argument T and K.
K specify the set of properties of T that should set to be required. When K is not provided, it should make all properties required just like the normal Required<T>.
For example
interface User {
name?: string
age?: number
address?: string
}
type UserRequiredName = RequiredByKeys<User, 'name'> // { name: string; age?: number; address?: string }
Change the following code to make the test cases pass (no type check errors).
interface User {
name?: string
age?: number
address?: string
}
interface UserRequiredName {
name: string
age?: number
address?: string
}
interface UserRequiredNameAndAge {
name: string
age: number
address?: string
}
type cases = [
Expect<Equal<RequiredByKeys<User, 'name'>, UserRequiredName>>,
Expect<Equal<RequiredByKeys<User, 'name' | 'age'>, UserRequiredNameAndAge>>,
Expect<Equal<RequiredByKeys<User>, Required<User>>>,
// @ts-expect-error
Expect<Equal<RequiredByKeys<User, 'name' | 'unknown'>, UserRequiredName>>,
]
Unlock 102+ medium, hard, and extreme challenges to master advanced TypeScript.
One-time payment. Lifetime access.
type Merge<T> = { [K in keyof T]: T[K] }
type RequiredByKeys<T, K extends keyof T = keyof T> = Merge<
Omit<T, K> & Required<Pick<T, K>>
>How it works:
K extends keyof T = keyof T constrains K to valid keys of T and defaults to all keys when K is not provided, matching the behavior of the built-in Required<T>.Pick<T, K> extracts only the properties specified by K, and Required<...> removes their optional modifiers.Omit<T, K> extracts the remaining properties that should stay unchanged (keeping their original optional/required status).Omit<T, K> & Required<Pick<T, K>> combines both parts, but intersection types are not displayed cleanly by TypeScript.Merge<T> helper flattens the intersection into a single object type using a mapped type { [K in keyof T]: T[K] }, which produces a clean, unified result that matches the expected test case types.This challenge helps you understand selective property modifier manipulation and intersection type flattening and how to apply these concepts in real-world scenarios.
This challenge is originally from here.