「Typescript之旅」: 一文盘点Typescript中23个内置类型工具! (建议收藏)
今日更文《一文盘点Typescript中23个内置类型工具! (建议收藏)》。
引言
TypeScript 是一种基于 JavaScript 的类型编程语言, 提供了严格的类型检查机制和类型推导能力,类型是Typescript的核心与难点。
在实际开发中,通过一个类型来创建另一个类型的需求并不少见。而Typescript给我们提供的内置类型工具可以帮助我们简化复杂的类型转换。本文将对ts内置的23个类型工具进行逐个解析。帮助大家在项目中更好的使用内置类型工具构造我们开发中想使用的类型!
01.Partial<Type>
作用:Partial
接收一个泛型类型Type
,并将Type
所有属性都设置为可选的,返回构造的新类型。
常用指数: ⭐️⭐️⭐️⭐️⭐️
使用场景示例(更新部分资源):
interface User {
name: string
age: number
address: string
}
function updateUser(user: User, fieldsToUpdate: Partial<User>) {
return { ...user, ...fieldsToUpdate }
}
const user: User = { name: 'xiaoming', age: 30, address: '上海' }
const newUser = updateUser(user, { address: '北京' })
源码实现:
/**
* Make all properties in T optional
*/
type Partial<T> = {
[P in keyof T]?: T[P];
};
02.Required<Type>
作用:Required
接收一个泛型类型Type
,并将Type
所有属性都设置为必选的,返回构造的新类型(Required的作用与Partial相反)。
常用指数: ⭐️⭐️⭐️⭐️⭐️
使用场景示例(验证输入数据):
interface Props {
name?: string
age?: number
}
function printProps(props: Required<Props>) {
console.log(`${props.name} is ${props.age} years old.`)
}
printProps({ name: 'xiaoming'}) // error ❗️
源码实现:
/**
* Make all properties in T required
*/
type Required<T> = {
[P in keyof T]-?: T[P];
};
03. Readonly<Type>
作用:Readonly
接收一个泛型类型Type
,并将Type
所有属性都设置为只读的,返回构造的新类型, 新类型的属性不可再进行分配。
常用指数: ⭐️⭐️⭐️⭐️⭐️
使用场景示例(对象初始化后防止其属性值被再次分配):
interface User {
name: string
age: number
}
const user: Readonly<User> = { name: 'xiaoming', age: 30 }
user.name = 'zhangsan' // error ❗️
源码实现:
/**
* Make all properties in T readonly
*/
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
拓展:
-
也通常与
Object.freeze
一起使用declare function freeze<Type>(obj: Type): Readonly<Type>;
04.Record<Keys, Type>
作用:构造一个对象类型,其属性键为Keys
,属性值为Type
。
常用指数: ⭐️⭐️⭐️⭐️⭐️
使用场景示例(创建具有一致性的字典):
interface User {
name: string
age: number
}
type UserName = 'xiaoming' | 'xiaohong' | 'xiaohuang'
const users: Record<UserName, User> = {
xiaoming: { name: 'ming', age: 23 },
xiaohong: { name: 'hong', age: 24 },
xiaohuang: { name: 'huang', age: 25 }
}
源码实现:
/**
* Construct a type with a set of properties K of type T
*/
type Record<K extends keyof any, T> = {
[P in K]: T;
};
05. Pick<Type, Keys>
作用: 从类型Type
中选择一组属性Keys
来创建类型。
常用指数: ⭐️⭐️⭐️⭐️⭐️
使用场景示例(从已有类型挑几个需要的属性构造新类型):
interface User {
name: string;
age: number;
address: string
}
type NameAndAgeOnly = Pick<User, 'name' | 'age'>;
const nameAndAgeOnly: NameAndAgeOnly = { name: 'xiaoming', age: 26 };
源码实现:
/**
* From T, pick a set of properties whose keys are in the union K
*/
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
扩展:
- 结合
pick
函数使用
const user = {name: 'xiaoming', age: 26, address: 'shanghai'}
declare function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K>;
const nameAndAgeOnly = pick(user, "name", "age"); // { name: string, age: number }
Pick
类型的Keys
泛型必须是在Type
中存在的.
06. Exclude<UnionType, ExcludedMembers>
作用: 从联合类型UnionType
中排除ExcludedMembers
类型然后返回一个新类型。
常用指数: ⭐️⭐️⭐️⭐️⭐️
使用场景示例:
interface User {
name: string;
age: number;
address: string
}
type UserExcludeAddress = Exclude<keyof User, 'address'> // "name" | "age"
源码实现:
/**
* Exclude from T those types that are assignable to U
*/
type Exclude<T, U> = T extends U ? never : T;
扩展:
Exclude
也可从对象联合类型中排出掉指定的选项
const user1 = { name: 'ming', age: 23, address: 'shanghai' } as const
const user2 = { name: 'hong', age: 24, address: 'beijing' } as const
const user3 = { name: 'huang', age: 25, address: 'shenzhen' } as const
type Users = typeof user1 | typeof user2 | typeof user3
type UsersExcludeMing = Exclude<Users, { name: 'ming' }>
07. Extract<Type, Union>
作用: 从联合类型Type
中提取Union
类型然后返回一个新类型。
常用指数: ⭐️⭐️⭐️⭐️
使用场景示例:
interface User {
name: string;
age: number;
address: string
}
type UserAddress = Extract<keyof User, 'address'> // address
type Person = {
name: string;
age: string;
}
const user: Extract<keyof User, keyof Person> = 'name' || 'age';
type SuccessCode = Extract<200 | 404, 200>; // 200
源码实现:
/**
* Extract from T those types that are assignable to U
*/
type Extract<T, U> = T extends U ? T : never;
扩展:
- 如果泛型
Type
中没有Union
, 返回never。
type SuccessCode = Extract<200 | 404, 204>; // never
08. Omit<Type, Keys>
作用: 与Pick
相反,Omit
是从Type
中选取所有Keys
属性然后删除构造一个新类型。
常用指数: ⭐️⭐️⭐️⭐️⭐️
使用场景示例:
interface User {
name: string;
age: number;
address: string
}
type UserOmitAge = Omit<User, 'address'>;
const userOmitAge: UserOmitAge = { name: 'xiaoming', age: 30 };
源码实现:
/**
* Construct a type with the properties of T except for those in type K.
*/
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
扩展:
- 从源码可以看出来
Omit
的实现其实就是Pick
和Exclude
的组合。因为Omit
的使用场景比较多,所以Typescript应使用者要求新增了Omit
工具类型。
09. NonNullable<Type>
作用: 通过从Type
中排除null
和undefined
来构造一个类型。
常用指数: ⭐️⭐️⭐️⭐️⭐️
使用场景示例:
type PortNumber = string | number | null;
type ServerPortNum = NonNullable<PortNumber>
源码实现:
/**
* Exclude null and undefined from T
*/
type NonNullable<T> = T & {};
10. Parameters<Type>
作用: 接受一个函数类型, 将函数的参数处理成一个元组类型。
常用指数: ⭐️⭐️⭐️⭐️⭐️
使用场景示例:
function createStudent(sno: string, name: string, age: number) {
return { sno, name, age }
}
type CreateStudentParams = Parameters<typeof createStudent>
const createStuParams: CreateStudentParams = ['112899022', 'ming', 30]
const stu1 = createStudent(...createStuParams)
源码实现:
/**
* Obtain the parameters of a function type in a tuple
*/
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
扩展:
-
Parameters
接收的泛型必须是一个函数类型,但是作为顶级类型any
和底层类型never
, Typescript对其有特殊的处理。type T1 = Parameters<any>; // unknown[] type T2 = Parameters<never>; // never
-
Typescript中定义的
Function
也不能被parameters
接收,看Function
的实现就知道了。type T7 = Parameters<Function>; // error
Function
的实现:interface Function { readonly name: string; }
-
如果函数是重载函数,那么返回的是最后一个函数的参数组成的元组类型
declare function stringOrNum(x: string): number;
declare function stringOrNum(x: number): string;
declare function stringOrNum(x: string | number): string | number;
type T1 = Parameters<typeof stringOrNum>; // [x: string | number]
11. ConstructorParameters<Type>
作用: 接受一个具有构造函数的类型, 将构造函数的参数处理成一个元组类型。
常用指数: ⭐️⭐️⭐️
使用场景示例:
class Test { constructor(a: number, b: string) {}}
type T1 = ConstructorParameters<typeof Test>; // [a: number, b: string]
type T2 = ConstructorParameters<new (x: string, y: number) => any> // [x: string, y: number]
源码实现:
/**
* Obtain the parameters of a constructor function type in a tuple
*/
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;
扩展:
class ArticleModel {
title: string
content?: string
constructor(title: string) {
this.title = title
}
}
class CreateInstance<T extends new (...args: any[]) => any> {
private ClassConstructor: T
constructor(ctr: T) {
this.ClassConstructor = ctr
}
getInstance(...args: ConstructorParameters<T>): InstanceType<T> {
return new this.ClassConstructor(...args)
}
}
const articleCache = new CreateInstance(ArticleModel)
const amazonArticle = articleCache.getInstance('typescript实用类型')
-
ConstructorParameters
也常用于获取内置构造方法或第三方库的参数类型type T3 = ConstructorParameters<ErrorConstructor> // [message?: string | undefined] type T4 = ConstructorParameters<FunctionConstructor> // string[] type T5 = ConstructorParameters<RegExpConstructor> // [pattern: string | RegExp, flags?: string | undefined]
-
对
any
和never
的特殊处理type T7 = ConstructorParameters<any>; type T8 = ConstructorParameters<never>;
12. ReturnType<Type>
作用: 获取函数类型的返回值类型。
常用指数: ⭐️⭐️⭐️⭐️⭐️
使用场景示例:
function getUser() {
return { name: 'ming', age: 30 }
}
type User = ReturnType<typeof getUser>
const user: User = { name: 'hong', age: 26 }
源码实现:
/**
* Obtain the return type of a function type
*/
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
扩展:
-
同
Parameters
类型一样,接收的泛型必须是一个函数类型 -
泛型是
any
和never
的情况type T1 = ReturnType<any>; // any type T2 = ReturnType<never>; // never
-
Function
不能被ReturnType
接收 -
如果函数是重载函数,那么返回的是最后一个函数的返回类型。
13. InstanceType<Type>
作用: 获取构造函数类型的返回类型(构造函数返回什么什么类型,InstanceType
获取的就是什么类型)。
常用指数: ⭐️⭐️⭐️⭐️
使用场景示例:
class Person {
constructor(public name: string) {}
}
type PersonInstance = InstanceType<typeof Person>
const person: PersonInstance = new Person('Alice')
interface User {
new (name: string): Object
}
type UserInstance = InstanceType<User> // Object
源码实现:
/**
* Obtain the return type of a constructor function type
*/
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
扩展:
-
InstanceType
也常用于获取内置构造方法或第三方库的参数类型type T3 = InstanceType<ErrorConstructor> // Error type T4 = InstanceType<FunctionConstructor> // Function type T5 = InstanceType<RegExpConstructor> // RegExp
-
对
any
和never
的特殊处理type T7 = InstanceType<any>; type T8 = InstanceType<never>;
-
一个vue的例子
<!-- MyModal.vue --> <script setup lang="ts"> import { ref } from 'vue' const isContentShown = ref(false) const open = () => (isContentShown.value = true) defineExpose({ open }) </script> // 为了获得MyModal的实例类型,使用InstanceType实用程序提取其实例类型 <!-- Other.vue --> <script setup lang="ts"> import MyModal from './MyModal.vue' const modal = ref<InstanceType<typeof MyModal> | null>(null) const openModal = () => { modal.value?.open() } </script>
14. Awaited<Type>
作用: 获取Promise中的类型(如await、then方法返回的被Promise包裹的数据的类型)。适合处理异步操作并确保解析值的类型安全。
常用指数: ⭐️⭐️⭐️⭐️⭐️
使用场景示例:
type A = Awaited<Promise<string>>; // string
type B = Awaited<Promise<Promise<number>>>; // number
// 假如这是一个第三方库,User没有导出,fetchUser函数导出了
interface User {
name: string
age: number
}
export async function fetchUser(): Promise<User> {
const data = await fetch('https://www.example.com/user').then(res => {
return res.json()
})
return data
}
// 我们开发中在获取到了User类型
type UserFetch = Awaited<ReturnType<typeof fetchUser>>
async function getUserInfo() {
let user: UserFetch = { name: 'ming', age: 30 }
return user
}
源码实现:
/**
* Recursively unwraps the "awaited type" of a type. Non-promise "thenables" should resolve to `never`. This emulates the behavior of `await`.
*/
type Awaited<T> = T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode
T extends object & { then(onfulfilled: infer F, ...args: infer _): any; } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped
F extends ((value: infer V, ...args: infer _) => any) ? // if the argument to `then` is callable, extracts the first argument
Awaited<V> : // recursively unwrap the value
never : // the argument to `then` was not callable
T; // non-object or non-thenable
扩展:
-
Awaited
是可以递归解Promise
type T1 = Awaited<Promise<Promise<Promise<Promise<Promise<number>>>>>> // number
-
如果传入
Awaited
的泛型不是Promise,那么会原样返回type T2 = Awaited<string> // string
15. ThisParameterType<Type>
作用: 提取函数类型的this参数的类型, 如果函数类型没有this参数, 返回unknown。
常用指数: ⭐️⭐️⭐️
使用场景示例:
function toHex(this: Number) {
return this.toString(16);
}
function numberToString(n: ThisParameterType<typeof toHex>) {
return toHex.apply(n);
}
源码实现:
/**
* Extracts the type of the 'this' parameter of a function type, or 'unknown' if the function type has no 'this' parameter.
*/
type ThisParameterType<T> = T extends (this: infer U, ...args: never) => any ? U : unknown;
16. OmitThisParameter<Type>
作用: 与ThisParameterType
相反, 排除函数类型的this
参数
常用指数: ⭐️⭐️⭐️
使用场景示例:
function toHex(this: Number) {
return this.toString(16);
}
const fiveToHex: OmitThisParameter<typeof toHex> = toHex.bind(5);
console.log(fiveToHex());
源码实现:
/**
* Removes the 'this' parameter from a function type.
*/
type OmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T;
17. ThisType<Type>
作用: 控制字面量对象中this
所表示的类型。 只在--noImplicitThis
下有用
常用指数: ⭐️⭐️⭐️
使用场景示例:
// 正常情况推导出来的this
type Point = {
x: number;
y: number;
moveBy(dx: number, dy: number): void;
}
let p: Point = {
x: 10,
y: 20,
moveBy(dx, dy) {
this.x += dx; // this has type Point
this.y += dy; // this has type Point
}
}
// 使用ThisType进行控制this
type Point = {
x: number;
y: number;
moveBy(dx: number, dy: number): void;
}
let p: ThisType<{x: number}> & Point = {
x: 10,
y: 20,
moveBy(dx, dy) {
this.x += dx; // this has type Point
this.y += dy; // error ❗️类型“{ x: number; }”上不存在属性“y”。
}
}
源码实现:
interface ThisType<T> {}
扩展:
对象字面值方法中的表达式this的类型按照下面的方法进行确定:
- 如果方法具有显式声明的this参数,则this具有该参数的类型。
- 否则,如果方法带了this参数,那么this就是这个。
- 否则,如果对象字面量有
ThisType<T>
的上下文类型,则该类型为T。 - 否则,如果不包含,那么就自动推导
- 否则,
this
就是any
18. ReadonlyArray<Type>
作用: 描述只能读的数组, 不可进行添加、删除、替换操作。
常用指数: ⭐️⭐️⭐️⭐️
使用场景示例:
function foo(arr: ReadonlyArray<string>) {
arr.slice(); // okay
arr.push("hello!"); // Type error
arr.pop(); // Type error
arr.splice(1, 1); // Type error
arr[0] = 'aa' // Type error
}
foo(['a','b','c'])
ReadonlyArray<string>
的简写:readonly string[]
源码实现:
interface ReadonlyArray<T> {
readonly length: number
toString(): string
toLocaleString(): string
concat(...items: ConcatArray<T>[]): T[]
concat(...items: (T | ConcatArray<T>)[]): T[]
join(separator?: string): string
slice(start?: number, end?: number): T[]
indexOf(searchElement: T, fromIndex?: number): number
lastIndexOf(searchElement: T, fromIndex?: number): number
every<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): this is readonly S[]
every(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): boolean
some(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): boolean
forEach(callbackfn: (value: T, index: number, array: readonly T[]) => void, thisArg?: any): void
map<U>(callbackfn: (value: T, index: number, array: readonly T[]) => U, thisArg?: any): U[]
filter<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): S[]
filter(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): T[]
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, initialValue: T): T
reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U
reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T
reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, initialValue: T): T
reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U
readonly [n: number]: T
}
19. Uppercase<StringType>
作用: 将字符串中的每个字符转换为对应的大写。
常用指数: ⭐️⭐️⭐️⭐️
使用场景示例:
type Greeting = 'Hello, world'
type ShoutyGreeting = Uppercase<Greeting> // "HELLO, WORLD"
type ASCIICacheKey<Str extends string> = `ID-${Uppercase<Str>}`
type MainID = ASCIICacheKey<'my_app'> // "ID-MY_APP"
源码实现:
/**
* Convert string literal type to uppercase
*/
type Uppercase<S extends string> = intrinsic;
21. Lowercase<StringType>
作用: 将字符串中的每个字符转换为对应的小写。
常用指数: ⭐️⭐️⭐️⭐️
使用场景示例:
type Greeting = 'Hello, world'
type QuietGreeting = Lowercase<Greeting> // "hello, world"
type ASCIICacheKey<Str extends string> = `id-${Lowercase<Str>}`
type MainID = ASCIICacheKey<'MY_APP'> // "id-my_app"
源码实现:
/**
* Convert string literal type to lowercase
*/
type Lowercase<S extends string> = intrinsic;
22. Capitalize<StringType>
作用: 将字符串中的第一个字符转换为大写字母。
常用指数: ⭐️⭐️⭐️⭐️
使用场景示例:
/**
* Convert first character of string literal type to lowercase
*/
type Uncapitalize<S extends string> = intrinsic;
源码实现:
/**
* Convert first character of string literal type to uppercase
*/
type Capitalize<S extends string> = intrinsic;
23. Uncapitalize<StringType>
作用: 将字符串中的第一个字符转换为小写字母。
常用指数: ⭐️⭐️⭐️⭐️
使用场景示例:
type UppercaseGreeting = "HELLO WORLD";
type UncomfortableGreeting = Uncapitalize<UppercaseGreeting>;
源码实现:
/**
* Convert first character of string literal type to lowercase
*/
type Uncapitalize<S extends string> = intrinsic;
优秀的类型库
我们应该都用过lodash,这是一个javascript版本的实用工具的库,能帮我们快速处理数据,在Typescript中有没有这样的静态类型的实用工具库呢?当然!
总结
Typescript提供的内置类型都是经过团队成员深思熟虑后添加的,通过提供的内置类型与组合内置类型可以覆盖广泛的使用场景。
往期文章
转载自:https://juejin.cn/post/7341669201009655845