Readonly Type#
Definition: Used to set all properties of type T
to read-only.
type Readonly<T> = {
readonly [P in keyof T]: T[P]
}
Usage:
interface Person {
name: string
age: number
}
const person: Readonly<Person> = {
name: 'Lucy',
age: 22,
}
// Will throw an error: Cannot assign to 'name' because it is a read-only property
person.name = 'Lily'
readonly
is read-only, properties marked withreadonly
can only be assigned during declaration or in the class constructor, and cannot be modified afterwards (i.e., read-only properties).
ReadonlyArray#
Definition: Used to set an array of type T
to read-only. Variables can only be assigned during array initialization, and the array cannot be modified afterwards.
interface ReadonlyArray<T> {
[Symbol.iterator](): IterableIterator<T>
entries(): IterableIterator<[number, T]>
keys(): IterableIterator<number>
values(): IterableIterator<T>
}
Usage:
interface Person {
name: string
}
const personList: ReadonlyArray<Person> = [{ name: 'Jack' }, { name: 'Rose' }]
// Will throw an error: Property 'push' does not exist on type 'readonly Person[]'
// personList.push({ name: 'Lucy' })
// However, if the internal elements are reference types, the elements themselves can be modified
personList[0].name = 'Lily'
Partial Type#
Definition: Used to set all properties of type T
to optional. First, it retrieves all properties of type T
using keyof T
, then iterates over them using the in
operator, and finally adds ?
after the properties to make them optional.
type Partial<T> = {
[P in keyof T]?: T[P]
}
Usage:
interface Organization {
id: number
name: string
address: string
type: string
nationality: string
}
const params: Partial<Organization> = {
address: '...new address',
}
// Same effect as above Partial
const params: Pick<Organization, 'address'> = {
address: '...new address',
}
Required Type#
Definition: The opposite of Partial<T>
, used to set all properties of type T
to required. First, it retrieves all properties of type T
using keyof T
, then iterates over them using the in
operator, and finally adds -
before the ?
to make the properties required.
type Required<T> = {
[P in keyof T]-?: T[P]
}
Usage:
interface Person {
name?: string
age?: number
}
// The new type returned after using Required mapping, name and age both become required properties
// Will throw an error: Type '{}' is missing the following properties from type 'Required<Person>': name, age
let person: Required<Person> = {}
Pick Type#
Definition: Extracts a subset of properties from type T
to create a new return type.
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
}
Usage:
interface Goods {
type: string
goodsName: string
price: number
}
// type RequestGoodsParams = {
// goodsName: string;
// price: number;
// }
type RequestGoodsParams = Pick<Goods, 'goodsName' | 'price'>
const params: RequestGoodsParams = {
goodsName: '',
price: 10,
}
Omit Type#
Definition: The opposite of Pick
, used to exclude certain properties from type T
and return a new type.
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
Usage:
interface Rectangular {
length: number
height: number
width: number
}
// type Square = {
// length: number;
// }
type Square = Omit<Rectangular, 'height' | 'width'>
Omit
inference process:
type Person = {
name: string
age: string
location: string
}
type PersonWithoutLocation = Omit<Person, 'location'>
// Inference
type PersonWithoutLocation = Pick<Person, Exclude<'name' | 'age' | 'location', 'location'>>
// Inference
type PersonWithoutLocation = Pick<
Person,
('name' extends 'location' ? never : 'name') | ('age' extends 'location' ? never : 'age') | ('location' extends 'location' ? never : 'location')
>
// Inference
type PersonWithoutLocation = Pick<Person, 'name' | 'age' | never>
// Inference
type PersonWithoutLocation = Pick<Person, 'name' | 'age'>
// Inference
type PersonWithoutLocation = {
[p in 'name' | 'age']: Person[p]
}
// Inference
type PersonWithoutLocation = {
name: string
age: string
}
Extract Type Extract<T,U>#
Definition: Extracts types from T
that can be assigned to U
.
type Extract<T, U> = T extends U ? T : never
Usage:
type T01 = Extract<'a' | 'b' | 'c' | 'd', 'a' | 'c' | 'f'> // 'a' | 'c'
type T02 = Extract<string | number | (() => void), Function> // () => void
Exclude Type Exclude<T,U>#
Definition: The opposite of Extract
, used to remove types from T
that can be assigned to U
.
type Exclude<T, U> = T extends U ? never : T
Usage:
type T00 = Exclude<'a' | 'b' | 'c' | 'd', 'a' | 'c' | 'f'> // 'b' | 'd'
type T01 = Exclude<string | number | (() => void), Function> // string | number
Record<K,T>#
Definition: Accepts two generics, where K
must be a type that can be assigned to string | number | symbol
. It iterates over K
using the in
operator, and each property's type must be of type T
.
type Record<K extends string | number | symbol, T> = {
[P in K]: T
}
Record
is a very useful generic type in TypeScript. It requires two specific parameter types, Record<K, V>
is used to specify the type of an object. All keys of the object are of type K
, and the values corresponding to these keys are all of type V
. If Record
type is not used, the following method may be needed to achieve the same effect:
type RecordExample = Record<string, number>
// Equivalent to
interface EquivalentExample {
[key: string]: number
}
Usage 1: Convert an array of Person
type into an object mapping:
interface Person {
name: string
age: number
}
const personList = [
{ name: 'Jack', age: 26 },
{ name: 'Lucy', age: 22 },
{ name: 'Rose', age: 18 },
]
const personMap: Record<string, Person> = {}
personList.forEach((person) => {
personMap[person.name] = person
})
Usage 2: When passing parameters, if you want the parameter to be an object but are unsure of the specific type, you can use Record
as the parameter type:
function doSomething(obj: Record<string, any>) {}
Usage 3: Write a function that converts all values in the parameter object to the corresponding numbers, ensuring that the input and output objects have the same keys:
type Input = Record<string, string>
function transform<T extends Input>(input: T): Record<keyof T, number> {
const keys: (keyof T)[] = Object.keys(input)
return keys.reduce((acc, key) => {
acc[key] = +input[key]
return acc
}, {} as Record<keyof T, number>)
}
However, it is important to note that when using union types, Record
itself also has limitations (this is a limitation of TypeScript itself). For example, with 'apple' | 'banana' | 'orange'
, if written this way, the following code will be incorrect:
type Fruit = 'apple' | 'banana' | 'orange'
type Price = Record<Fruit, number>
// type error
const prices: Price = {
apple: 20,
}
Record
does not inherently solve the case of optional keys. Record<'A' | 'B', number>
means that both A and B need to be keys of this type, not that only one of A or B can be a key. For such optional cases, you can wrap it with Partial
to meet the requirement:
type Price = Partial<Record<Fruit, number>>
// correct
const prices: Price = {
apple: 20,
}
NonNullable Type#
Definition: Removes null
, undefined
, and never
types from T
, but does not remove void
or unknown
types.
type NonNullable<T> = T extends null | undefined ? never : T
Usage:
type T01 = NonNullable<string | number | undefined> // string | number
type T02 = NonNullable<(() => string) | string[] | null | undefined> // (() => string) | string[]
type T03 = NonNullable<{ name?: string; age: number } | string[] | null | undefined> // {name?: string, age: number} | string[]
ConstructorParameters Type#
Definition: Returns a tuple type composed of the parameter types of the constructor in a class.
type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never
Usage:
class Person {
name: string
age: number
gender: 'man' | 'women'
constructor(name: string, age: number, gender: 'man' | 'women') {
this.name = name
this.age = age
this.gender = gender
}
}
type ConstructorType = ConstructorParameters<typeof Person> // [name: string, age: number, gender: 'man' | 'women']
const params: ConstructorType = ['Jack', 20, 'man']
InstanceType#
Definition: Gets the return type of a class constructor.
type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any
Usage:
class Person {
name: string
age: number
gender: 'man' | 'women'
constructor(name: string, age: number, gender: 'man' | 'women') {
this.name = name
this.age = age
this.gender = gender
}
}
type Instance = InstanceType<typeof Person> // Person
const params: Instance = {
name: 'Jack',
age: 20,
gender: 'man',
}
Parameters Type#
Definition: Gets a tuple type composed of the parameter types of a function.
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
Usage:
type FunctionType = (name: string, age: number) => boolean
type FunctionParamsType = Parameters<FunctionType> // [name: string, age: number]
const params: FunctionParamsType = ['Jack', 20]
ReturnType Type#
Definition: Gets the return type of a function.
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Usage:
type FunctionType = (name: string, age: number) => boolean | string
type FunctionReturnType = ReturnType<FunctionType> // boolean | string