Typescript Utility Type Partial Expect
Posted on: September 5, 2022
How to Transform your Type to Have All Fields Optional Expected Selected Fields to be Required?
The situation is that you want to transform an existing type into all optional fields except a subset of the fields to be required. A use case is that you wish to have all fields except the primary key and many other keys you know must always be present.
Example Type
We need to create a custom TypeScript utility type to have this new type. But first, let's make a testing type.
1interface MyType {2 a: string;3 b: string;4 c: string;5}
Breaking Down the Utility Types
The result is more straightforward if we break the work into smaller chunks. In other words, we break down the utility types into several utility types. Then, combining the utility types allows us to get the sum of the transformation.
The result is the combination of two operations: picking required fields and picking optional fields.
Picking Required Fields
To pick the required field, we can take a subset of the fields depending of what the developer specifies as required properties of a type.
1type RequiredFielsd<T, K extends keyof T> = Required<Pick<T, K>>;
The first utility type uses two native TypeScript's utility types: Pick
and Required
.
The Pick
extracts from an existing type T
fields specified.
1type MyOtherType1 = RequiredFielsd<MyType, "a">;2type MyOtherType2 = RequiredFielsd<MyType, "a" | "b">;
These two examples create one type that has only a property name a
from the original type that has a a
and make it required. The second example creates another type with a
and b
fields required. No c
field.
Picking Optional Fields
The second step is to extract the optional field. Similar to the first part, we will leverage the existing Pick
. In this type, we will not take the field the user specify but the rest of the field (opposite).
1type PartialFields<T, K extends keyof T> = Partial<Pick<T, Exclude<keyof T, K>>>;
The utility type picks all fields that are not specified in k
. Then, marks them as optional ( | undefined
).
1type MyOtherType3 = PartialFields<MyType, "a">;
The result of this new type is a type with b
and c
that will be both string | undefined
. No a
.
Combining the Utility Functions
Now, we need to combine both.
1type PartialExcept<T, K extends keyof T> = RequiredFielsd<T, K> & PartialFields<T, K>;
Using the same T
with the same K
means that the RequiredFielsd
will take the fields specified and mark them as required while all the other fields will be set as optional.
1type MyFinalType = PartialExcept<MyType, "a">;2const test: MyFinalType = {3 a: "Required Value"4};
The result is a new type with only a
required with two optional fields.
Conclusion
The best tip when working with TypeScript is to break them down into small transformers. Breaking the utility functions makes it easier to understand while creating and later when maintaining. Furthermore, you can reuse a subset of the transformers in another part of your system.
You can find the code in this post in the TypeScript Playground