Last updated: Feb 28, 2024
Reading timeยท3 min
To make an optional property required, create a utility type that uses a mapping modifier to remove the optionality for the specified property.
The new type will have the specified property marked as required.
interface Employee { id?: number; name: string; salary?: number; } type WithRequiredProperty<Type, Key extends keyof Type> = Type & { [Property in Key]-?: Type[Property]; }; // ๐๏ธ Make salary required const emp1: WithRequiredProperty<Employee, 'salary'> = { name: 'Bobby Hadz', salary: 100, };
We created a utility type that takes a type and a property name and makes the property required.
You can use the utility type to make more than one property required by separating their names with a pipe.
interface Employee { id?: number; name: string; salary?: number; } type WithRequiredProperty<Type, Key extends keyof Type> = Type & { [Property in Key]-?: Type[Property]; }; // ๐๏ธ Make `salary` and `id` required const emp1: WithRequiredProperty<Employee, 'salary' | 'id'> = { id: 0, name: 'Bobby Hadz', salary: 100, };
The -?:
syntax is called a
mapping modifier
is used to affect optionality.
It is used in the built-in Required utility type which looks like this:
/** * Make all properties in T required */ type Required<T> = { [P in keyof T]-?: T[P]; };
In our case, we only make a single property required.
interface Employee { id?: number; name: string; salary?: number; } type WithRequiredProperty<Type, Key extends keyof Type> = Type & { [Property in Key]-?: Type[Property]; }; const emp1: WithRequiredProperty<Employee, 'salary'> = { name: 'Bobby Hadz', salary: 100, };
An alternative and perhaps easier-to-read solution is to extend the type alias or interface and override the properties you want to set to required.
Alternatively, you can extend the interface or type alias, creating a new interface where you set the optional properties to required.
interface Employee { id?: number; name: string; salary?: number; } interface EmployeeWithSalary extends Employee { salary: number; // ๐๏ธ is now required id: number; // ๐๏ธ is now required } const emp2: EmployeeWithSalary = { id: 1, name: 'Bobby Hadz', salary: 200, };
The EmployeeWithSalary
interface extends Employee
and overrides the salary
and id
properties, setting them to required.
If any of the required properties are omitted, we will get a type-checking error.
interface Employee { id?: number; name: string; salary?: number; } interface EmployeeWithSalary extends Employee { salary: number; // ๐๏ธ is now required id: number; // ๐๏ธ is now required } // โ๏ธ Error: Property 'id' is missing in type // '{ name: string; salary: number; }' but // required in type 'EmployeeWithSalary'.ts(2741) const emp2: EmployeeWithSalary = { name: 'Bobby Hadz', salary: 200, };
Use the Required
utility type to make all of the properties in a type
required.
interface Employee { id?: number; name?: string; salary?: number; } const emp: Required<Employee> = { id: 1, name: 'Bobby Hadz', salary: 1000, };
The Required
utility type constructs a new type with all properties of the
provided type set to required.
interface Employee { id?: number; name?: string; salary?: number; } // ๐๏ธ type T = { // id: number; // name: string; // salary: number; // } type T = Required<Employee>;
You can see how the built-in Required
type is implemented in TypeScript's
Github repository.
/** * Make all properties in T required */ type Required<T> = { [P in keyof T]-?: T[P]; };
The -?:
syntax is called a
mapping modifier
and is used to affect optionality.
When prefixed with a minus, the mapping modifier removes the optionality of the type's properties.
Mapping modifiers can affect optionality both ways, e.g. you can also use them
to make all of the properties of a type optional by prefixing the ?:
with a
plus (+?:
).
If you don't add a prefix, then +
is assumed.
/** * Make all properties in T optional */ type Partial<T> = { [P in keyof T]?: T[P]; };
This is the code for the Partial utility type, which makes all of the properties in a type optional.
Notice that the only difference between the two types is the minus in front of
the question mark in the Required
type.
The -?:
syntax removes optionality whereas, ?:
(or +?:
) makes all
properties in the type optional.
You can learn more about the related topics by checking out the following tutorials: