You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// 创建一个接口interfacePerson{name: string;age: number;jobTitle: string;hobbies: string[];}// 使用 Person 接口创建对象constjack: Person={name: 'Jack',age: 33,jobTitle: 'CTO',hobbies: ['reading']}// 这是 ok,因为 “jack”对象包含在 Person 接口中指定的所有属性。// 使用 Person 接口创建新对象constlucy: Person={name: 'Lucy',age: 18,}// TS error: Type '{ name: string; age: number; }' is missing the following properties from type 'Person': jobTitle, hobbies// 使用 Partial<Type> 和 Person 接口使 Person 接口中的所有属性都是可选的constlucy: Partial<Person>={name: 'Lucy',age: 18,}
初次使用 Exclude<Type, ExcludedUnion> 可能有点令人困惑。这个实用工具类型所做的是,用于从类型 Type 中取出不在 ExcludedUnion 类型中的成员。
// 创建 Colors 类型:typeColors='white'|'blue'|'black'|'red'|'orange'|'grey'|'purple';typeColorsWarm=Exclude<Colors,'white'|'blue'|'black'|'grey'>;// 把 ColorsWarm 转化成:// type ColorsWarm = "red" | "orange" | "purple";typeColorsCold=Exclude<Colors,'red'|'orange'|'purple'>;// 把 ColorsCold 转化成:// type ColorsCold = "white" | "blue" | "black" | "grey"// 创建 varmColor:constvarmColor: ColorsWarm='red'// 创建 coldColor:constcoldColor: ColorsCold='blue'// 尝试混合:constcoldColorTwp: ColorsCold='red'// TS error: Type '"red"' is not assignable to type 'ColorsCold'.
Extract
语法:Extract<Type, Union>
发布:2.8 版本
实现:
typeExtract<T,U>=TextendsU ? T : never;
Extract<Type, Union> 类型执行与 Exclude<Type, ExcludedUnion> 类型相反的操作。用于从类型 Type 中取出可分配给 Union 类型的成员。有点类似集合里的交集概念。使用 Extract 之后,返回 Type 和 Union 交集。
typeFood='banana'|'pear'|'spinach'|'apple'|'lettuce'|'broccoli'|'avocado';typeFruit=Extract<Food,'banana'|'pear'|'apple'>;// 把 Fruit 转换成:// type Fruit = "banana" | "pear" | "apple";typeVegetable=Extract<Food,'spinach'|'lettuce'|'broccoli'|'avocado'>;// 把 Vegetable 转换成:// type Vegetable = "spinach" | "lettuce" | "broccoli" | "avocado";// 创建 someFruit:constsomeFruit: Fruit='pear'// 创建 someVegetable:constsomeVegetable: Vegetable='lettuce'// 尝试混合:constnotReallyAFruit: Fruit='avocado'// TS error: Type '"avocado"' is not assignable to type 'Fruit'.
NonNullable
语法:NonNullable<Type>
发布:2.8 版本
实现:
typeNonNullable<T>=Textendsnull|undefined ? never : T;
// 创建类型:typeprop=string|number|string[]|number[]|null|undefined;// 基于以前的类型创建新类型,不包括 null 和 undefined:typevalidProp=NonNullable<prop>// 把 validProp 转换成:// type validProp = string | number | string[] | number[]// 这是有效的:letuse1: validProp='Jack'letuse2: validProp=null// TS error: Type 'null' is not assignable to type 'validProp'.
Parameters
语法:Parameters<Type>
发布:3.1 版本
实现:
typeParameters<Textends(...args: any)=>any>=Textends(...args: infer P)=>any ? P : never;
Parameters 类型返回一个 Tuple 类型,其中包含作为 Type 传递的形参函数的类型。这些参数的返回顺序与它们在函数中出现的顺序相同。注意,Type 参数,对于 this 和以下类型,是一个函数 ((…args) =>type),而不是一个类型,比如 string。
// 声明函数类型:declarefunctionmyFunc(num1: number,num2: number): number;// 使用 Parameter<type> 从 myFunc 函数的参数创建新的 Tuple 类型:typemyFuncParams=Parameters<typeofmyFunc>;// 把 myFuncParams 转换成:// type myFuncParams = [num1: number, num2: number];// 这是有效的:letsomeNumbers: myFuncParams=[13,15];letsomeMix: myFuncParams=[9,'Hello'];// TS error: Type 'string' is not assignable to type 'number'.// 使用 Parameter<type> 从函数的参数创建新的 Tuple 类型:typeStringOnlyParams=Parameters<(foo: string,fizz: string)=>void>;// 把 StringOnlyParams 转换成:// type StringOnlyParams = [foo: string, fizz: string];// 这是有效的:letvalidNamesParams: StringOnlyParams=['Jill','Sandy'];letinvalidNamesParams: StringOnlyParams=[false,true];// TS error: Type 'boolean' is not assignable to type 'string'.
ConstructorParameters
语法:ConstructorParameters<Type>
发布:3.1 版本
实现:
typeConstructorParameters<Textendsabstractnew(...args: any)=>any>=Textendsabstractnew(...args: infer P)=>any ? P : never;
ConstructorParameters 类型与 Parameters 类型非常相似。这两者之间的区别在于, Parameters 从函数参数中获取类型,而ConstructorParameters 从作为 Type 参数传递的构造函数(Constructor)中获取类型。
// 创建一个 class:classHuman{publicnamepublicagepublicgenderconstructor(name: string,age: number,gender: string){this.name=name;this.age=age;this.gender=gender;}}// 创建基于 Human 构造函数类型:typeHumanTypes=ConstructorParameters<typeofHuman>// 把 HumanTypes 转换成:// type HumanTypes = [name: string, age: number, gender: string]constjoe: HumanTypes=['Joe',33,'male']constsandra: HumanTypes=['Sandra',41,'female']constthomas: HumanTypes=['Thomas',51]// TS error: Type '[string, number]' is not assignable to type '[name: string, age: number, gender: string]'.// Source has 2 element(s) but target requires 3.// 创建基于 String 构造函数类型:typeStringType=ConstructorParameters<StringConstructor>// 把 StringType 转换成:// type StringType = [value?: any]
ReturnType
语法:ReturnType<Type>
发布:2.8 版本
实现:
typeReturnType<Textends(...args: any)=>any>=Textends(...args: any)=> infer R ? R : any;
ReturnType 也类似于 Parameters 类型。这里的不同之处在于,ReturnType 提取作为 type 参数传递的函数的返回类型。
// 声明函数类型:declarefunctionmyFunc(name: string): string;// 使用 ReturnType<Type> 从 myFunc 类型中提取返回类型:typeMyFuncReturnType=ReturnType<typeofmyFunc>;// 把 MyFuncReturnType 转换成:// type MyFuncReturnType = string;// 这是有效的:letname1: MyFuncReturnType='Types';// 这是有效的:letname2: MyFuncReturnType=42;// TS error: Type 'number' is not assignable to type 'string'.typeMyReturnTypeBoolean=ReturnType<()=>boolean>// 把 MyReturnTypeBoolean 转换成:// type MyReturnTypeBoolean = boolean;typeMyReturnTypeStringArr=ReturnType<(num: number)=>string[]>;// 把 MyReturnTypeStringArr 转换成:// type MyReturnTypeStringArr = string[];typeMyReturnTypeVoid=ReturnType<(num: number,word: string)=>void>;// 把 MyReturnTypeVoid 转换成:// type MyReturnTypeVoid = void;
InstanceType
语法:InstanceType<Type>
发布:2.8 版本
实现:
typeInstanceType<Textendsabstractnew(...args: any)=>any>=Textendsabstractnew(...args: any)=> infer R ? R : any;
Instancetype 有点复杂。它所做的就是从作为 Type 参数传递的构造函数的实例类型创建一个新类型。如果使用一个常规类来处理类,则可能不需要此实用工具类型。可以只使用类名来获取所需的实例类型。
// 创建一个 class:classDog{name='Sam'age=1}typeDogInstanceType=InstanceType<typeofDog>// 把 DogInstanceType 转换成:// type DogInstanceType = Dog// 类似于使用 class 声明:typeDogType=Dog// 把 DogType 转换成:// type DogType = Dog
ThisParameterType
语法:ThisParameterType<Type>
发布:3.3 版本
实现:
typeThisParameterType<T>=Textends(this: infer U, ...args: any[])=>any ? U : unknown;
ThisParameterType 提取了作为 Type 参数传递的函数的 this 形参的使用类型。如果函数没有这个参数,实用工具类型将返回unknown。
// 创建一个使用 this 参数函数:functioncapitalize(this: String){returnthis[0].toUpperCase+this.substring(1).toLowerCase()}// 创建基于 this 参数的 capitalize函数类型:typeCapitalizeStringType=ThisParameterType<typeofcapitalize>// 把 CapitalizeStringType 转换成:// type CapitalizeStringType = String// 创建一个不使用 this 参数函数:functionsayHi(name: string){return`Hello, ${name}.`}// 创建基于不带 this 参数的 printUnknown 函数类型:typeSayHiType=ThisParameterType<typeofsayHi>// 把 SayHiType 转换成:// type SayHiType = unknown
OmitThisParameter
语法:OmitThisParameter<Type>
发布:3.3 版本
实现:
typeOmitThisParameter<T>=unknownextendsThisParameterType<T> ? T : Textends(...args: infer A)=> infer R ? (...args: A)=>R : T;
OmitThisParameter 实用类型执行与前面类型相反的操作。它通过 Type 接受一个函数类型作为参数,并返回不带 this 形参的函数类型。
// 创建一个使用 this 参数函数:functioncapitalize(this: String){returnthis[0].toUpperCase+this.substring(1).toLowerCase()}// 根据 capitalize 函数创建类型:typeCapitalizeType=OmitThisParameter<typeofcapitalize>// 把 CapitalizeStringType 转换成:// type CapitalizeType = () => string// 创建一个不使用 this 参数函数:functionsayHi(name: string){return`Hello, ${name}.`}// 根据 Sayhi 函数创建类型:typeSayHiType=OmitThisParameter<typeofsayHi>// 把 SayHiType 转换成:// type SayHiType = (name: string) => string
ThisType
语法:ThisType<Type>
发布:2.3 版本
实现:
interfaceThisType<T>{}
ThisType 实用工具类型允许显式地设置 this 上下文。可以使用它为整个对象字面量或仅为单个函数设置此值。在尝试此操作之前,请确保启用了编译器标志 --noImplicitThis。
// 创建 User 对象接口:interfaceUser{username: string;email: string;isActivated: boolean;printUserName(): string;printEmail(): string;printStatus(): boolean;}// 创建用户对象,并将 ThisType 设置为 user interface:constuserObj: ThisType<User>={username: 'Jiayi',email: '[email protected]',isActivated: false,printUserName(){returnthis.username;},printEmail(){returnthis.email;},printStatus(){returnthis.isActivated;}}
// 创建 User 接口:interfaceUser{username: string;password: string;}// 创建 SuperUser 接口:interfaceSuperUser{clearanceLevel: string;accesses: string[];}// 结合 User 和 SuperUser 创建 RegularUser 类型// 让 User 属性必需的和 SuperUser 属性可选的:typeRegularUser=Required<User>&Partial<SuperUser>// 这是有效的:constjack: RegularUser={username: 'Jack',password: 'some_secret_password_unlike_123456',}// 这是有效的:constjason: RegularUser={username: 'Jason',password: 'foo_bar_usually-doesnt_work-that_well',clearanceLevel: 'A'}// 这将抛出异常:constjim: RegularUser={username: 'Jim'}// TS error: Type '{ username: string; }' is not assignable to type 'RegularUser'.// Property 'password' is missing in type '{ username: string; }' but required in type 'Required<User>'
TypeScript 对于许多 Javascript 开发人员来说是难以理解的。引起麻烦的一个领域是高级类型。这个领域的一部分是 TypeScript 中内置的实用程序类型。它们可以帮助我们从现有类型中创建新的类型。在本文中,我们将了解其中一些实用工具类型如何工作以及如何使用它们。
实用工具类型简要介绍
TypeScript 为处理类型提供了一个强大的系统。这里有一些基本类型我们已经从 JavaScript 中了解。例如,数据类型如
number
,string
,boolean
,obejct
,symbol
,null
,undefined
。这并不是 TypeScript 提供的所有功能。在这些类型之上还有一些内置实用工具类型。有时候,这些实用工具类型也是最难以理解的。当初次看到这些类型时尤为明显。好消息是,如果你理解一个重要的事情,这些类型实际上并不困难。
所有这些内置实用工具类型实际上都是简单的函数,能看这篇文章,说明你已经从 JavaScript 中知道的函数。这里的主要区别是,工具函数处理业务,这些实用工具类型,只处理类型。这些工具类型所做的就是将类型从一种类型转换为另一种类型。
这个输入是开始时使用的某种类型。还可以提供多种类型。接下来,该工具类型将转换该输入并返回适当的输出。所发生的转换类型取决于使用的实用工具类型。
Typescipt 内置了 16 个工具类型 和 4 个字符串类型(只能在字符串中使用,这里暂时不介绍它们),接下来我们就来:
Let's learn them one by one!
关于语法
TypeScript 中的所有实用工具类型都使用类似的语法。这将使我们更容易学习和记住它。如果我们尝试将这些类型看作类似于函数的东西,也会使它更容易。这通常有助于更快地理解语法,有时要快得多。关于语法。
每个实用工具类型都以类型的名称开始。这个名字总是以大写字母开头。名称后面是左尖和右尖的尖括号,小于和大于符号(<>)。括号之间是参数。这些参数是我们正在使用的类型,即输入。Typescipt 把这种语法叫泛型
GenericType<SpecificType>
。仔细想想,使用实用程序类型就像调用一个函数并传递一些东西作为参数。这里的一个不同之处在于该函数始终以大写字母开头。第二个区别是,在函数名之后没有使用圆括号,而是使用尖括号。函数调用:
fn(a, b)
有些类型需要一个参数,有些则需要两个或者更多。与 JavaScript 函数参数类似,这些参数由冒号(,)分割,并在尖括号之间传递。下面这个简单的例子说明了普通函数和 TypeScript 实用工具类型之间的相似性。
关于可用性
我们将要学习的类型在 TypeScript 4.0 及以上版本中全部可用。确保你使用这个版本。否则,下面的一些类型可能无法工作,或者没有一些额外的包就无法工作。
Partial
Partial<Type>
创建
type
或interface
时,所有在内部定义的类型都需要作为默认值。如果我们想将某些标记为可选的,我们可以使用?
并将其放在属性名称之后。这将使该属性成为可选的。如果希望所有属性都是可选的,那么必须将所有属性都加上
?
。我们可以这样做:它也会对与该
interface
一起工作的一切产生影响。我们可以使用的另一个选项是Partial<Type>
。该类型接受一个参数,即希望设置为可选的类型。它返回相同的类型,但其中所有先前必需的属性现在都是可选的。// 这也会有效:
const alan: Partial = {}
// Partial 之后的 Person 接口:
// interface Person {
// name?: string;
// age?: number;
// jobTitle?: string;
// hobbies?: string[];
// }
Required
Required<Type>
Required<Type>
与Partial<Type>
正好相反。如果Partial<Type>
使所有属性都是可选的,则Required<Type>
使它们都是必需的、不可选的。Required<Type>
的语法与Partial<Type>
相同。唯一的区别是实用工具类型的名称。Readonly
Readonly<Type>
有时我们希望使某些数据不可变,防止他们被修改了。
Readonly<Type>
类型可以帮助我们对整个类型进行这种更改。例如,可以将接口中的所有属性设置为只读。当我们在某个对象中使用该接口,并试图改变某个对象的属性时,TypeScript 会抛出一个错误。Record
Record<Keys, Type>
假设我们有一组属性名和属性值。也就是我们常常在 Javascript 中使用的
{key: value}
。基于此数据,Record<Keys, Type>
允许我们创建键值对的记录。Record<Keys, Type>
通过将keys
参数指定的所有属性类型与Type
参数指定的值类型进行映射,基本上创建了一个新接口。Pick
Pick<Type, Keys>
假设我们只想使用现有接口的一些属性。可以做的一件事是创建新接口,只使用这些属性。另一个选项是使用
Pick<Type, Keys>
。Pick
类型允许我们获取现有类型(type),并从中只选择一些特定的键(keys),而忽略其余的。这个类型和 lodash.pick 工具函数功能一样,如果你理解这个函数,那么对于这个类型理解就很轻松了。Omit
Omit<Type, Keys>
Omit<Type, Keys>
基本上是一个相反的Pick<Type, Keys>
。我们指定某些类型作为type
的参数,但不是选择我们想要的属性,而是选择希望从现有类型中省略的属性。这个类型和 lodash.omit 工具函数功能一样,如果你理解这个函数,那么对于这个类型理解就很轻松了。Exclude
Exclude<Type, ExcludedUnion>
初次使用
Exclude<Type, ExcludedUnion>
可能有点令人困惑。这个实用工具类型所做的是,用于从类型Type
中取出不在ExcludedUnion
类型中的成员。Extract
Extract<Type, Union>
Extract<Type, Union>
类型执行与Exclude<Type, ExcludedUnion>
类型相反的操作。用于从类型Type
中取出可分配给Union
类型的成员。有点类似集合里的交集概念。使用Extract
之后,返回Type
和Union
交集。NonNullable
NonNullable<Type>
NonNullable
实用工具类型的工作原理与Exclude
类似。它接受指定的某种类型,并返回该类型,但不包括所有null
和undefined
类型。Parameters
Parameters<Type>
Parameters
类型返回一个 Tuple 类型,其中包含作为Type
传递的形参函数的类型。这些参数的返回顺序与它们在函数中出现的顺序相同。注意,Type
参数,对于this
和以下类型,是一个函数((…args) =>type)
,而不是一个类型,比如string
。ConstructorParameters
ConstructorParameters<Type>
ConstructorParameters
类型与Parameters
类型非常相似。这两者之间的区别在于,Parameters
从函数参数中获取类型,而ConstructorParameters
从作为Type
参数传递的构造函数(Constructor)中获取类型。ReturnType
ReturnType<Type>
ReturnType
也类似于Parameters
类型。这里的不同之处在于,ReturnType
提取作为type
参数传递的函数的返回类型。InstanceType
InstanceType<Type>
Instancetype
有点复杂。它所做的就是从作为Type
参数传递的构造函数的实例类型创建一个新类型。如果使用一个常规类来处理类,则可能不需要此实用工具类型。可以只使用类名来获取所需的实例类型。ThisParameterType
ThisParameterType<Type>
ThisParameterType
提取了作为Type
参数传递的函数的this
形参的使用类型。如果函数没有这个参数,实用工具类型将返回unknown
。OmitThisParameter
OmitThisParameter<Type>
OmitThisParameter
实用类型执行与前面类型相反的操作。它通过Type
接受一个函数类型作为参数,并返回不带this
形参的函数类型。ThisType
ThisType<Type>
ThisType
实用工具类型允许显式地设置this
上下文。可以使用它为整个对象字面量或仅为单个函数设置此值。在尝试此操作之前,请确保启用了编译器标志--noImplicitThis
。联合工具类型
TypeScript 内置实用工具类型的一个好处是,我们可以自由组合它们。可以将一种实用工具类型与另一种实用工具类型组合。还可以将一种实用工具类型与其他类型组合。例如,可以将类型与联合或交集类型组合。
扩展内置实用工具类型
虽然上面的内置实用工具类型令人惊叹,但它们并没有涵盖所有的用例,这就是提供更多实用工具的库填补空白的地方。此类库的一个很好的例子是 type-fest,它提供了更多的实用程序。
说在最后
在本文中,我们学习了 Typescript 实用工具类型,以及它们如何帮助我们从现有的类型中自动创建类型,而不会导致重复,从而无需保持相关类型的同步。我们列举一些内置的实用工具类型,我认为它们在我作为开发人员的日常工作中特别有用。在此基础上,我们推荐了
type-fest
,这是一个包含许多扩展内置类型的实用程序类型的库。今天就到这里吧,伙计们,玩得开心,祝你好运。
The text was updated successfully, but these errors were encountered: