An elegant solution for implementing optional property types using TypeScript
- Published on
- Published on
- /2 mins read/––– views
When developing a TypeScript project, defining types and interfaces is a basic and important task. However, we often encounter such scenarios:
For some data object attributes, not all fields need to be passed. This leads to a common type annotation problem.
Suppose we have an interface that represents a user:
interface User {
username: string
email: string
phone: string
address: string
age: number
}
When creating a user, you may not need all attributes to be created. We generally need to define a separate interface for this case:
interface CreateUserOptions {
username: string
email: string
phone?: string
address?: string
age?: number
}
function createUser(options: CreateUserOptions): User {
// TODO
}
It is obvious that there is a relationship between the two types, so I hope that the CreateUserOptions
type can be automatically generated according to the Article
type. Some properties in CreateUserOptions
are optional.
But unfortunately Typescript does not provide such syntax, so we have to implement this function manually.
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
So we can use it like this:
type CreateUserOptions = Optional<Article, 'author' | 'date' | 'readCount'>
Explain the principle of this type:
Omit<T, K>
: exclude theK
property fromT
.Omit<UserProfile, 'phone' | 'address' | 'age'> // Result: { username: string; email: string; }
Pick<T, K>
: PickK
attributes fromT
.Pick<UserProfile, 'phone' | 'address' | 'age'> // Result: { phone: string; address: string; age: number; }
Partial<T>
: Make all properties inT
optional.Partial<Pick<UserProfile, 'phone' | 'address' | 'age'>> // Result: { phone?: string; address?: string; age?: number; }
Type merging: Use the intersection type
&
to mergeOmit<T, K>
andPartial<Pick<T, K>>
to form the final Result:type CreateUserOptions = Optional<User, 'phone' | 'address' | 'age'>