TypeScript的官方文档已经更新了,但是我能找到的中文文档还是旧版本。因此,对一些新增和修改的章节进行了翻译和整理。本译文整理自TypeScriptHandbook中的“EverydayTypes”一章。本文并没有严格按照原文翻译,部分内容也做了说明和补充。类型别名(TypeAliases)我们已经学会了在类型注解中直接使用对象类型和联合类型,这很方便,但是有时候,一个类型会被多次使用,我们更愿意通过一个名字来引用它。这就是类型别名(typealias)。所谓类型别名,顾名思义,就是一个可以指代任何类型的名字。类型别名的语法是:typePoint={x:number;y:数字;};//和前面的例子完全一样console.log("坐标的y值为"+pt.y);}printCoord({x:100,y:100});你可以使用类型别名来给任何类型起一个名字,例如,命名为联合类型:typeID=number|细绳;注意,别名只是别名,不能使用类型别名来创建同一类型的不同版本。当您使用类型别名时,它与您编写的类型相同。换句话说,看起来非法的代码对于TypeScript来说仍然是合法的,因为这两种类型都是同一类型的别名:typeUserInputSanitizedString=string;functionsanitizeInput(str:string):UserInputSanitizedString{returnsanitize(str);}//创建一个经过清理的输入userInput=sanitizeInput(getInput());//虽然userInput="newinput";仍然可以重新分配一个字符串Interfaces接口声明被命名为对象类型另一种方式:interfacePoint{x:number;y:number;}functionprintCoord(pt:Point){console.log("坐标的x值为"+pt.x);console.log("坐标的y值为"+pt.y);}printCoord({x:100,y:100});就像我们在上一节中使用的类型别名一样,这个例子也可以正常工作,就像我们使用相同类型的匿名对象一样。TypeScript只关心传递给printCoord的值的结构——该值是否具有预期的属性。正是这种只关心类型的结构和能力的特性,我们认为TypeScript是一个结构化的类型系统。类型别名和接口非常相似,大多数时候,您可以随意使用。接口的几乎所有特性都可以在类型中使用。两者之间的主要区别在于类型别名本身不能添加新属性,而接口可以扩展。//Interface//通过继承接口扩展类型Animal{name:string}interfaceBearextendsAnimal{honey:boolean}constbear=getBear()bear.namebear.honey//Type//通过交集扩展类型typeAnimal={name:string}typeBear=Animal&{honey:boolean}constbear=getBear();bear.name;bear.honey;//Interface//添加一个新字段到一个已有的界面interfaceWindow{title:string}interfaceWindow{ts:TypeScriptAPI}constsrc='consta="HelloWorld"';window.ts.transpileModule(src,{});//Type//创建后不能更改typeWindow={title:string}typeWindow={ts:TypeScriptAPI}//错误:重复标识符'Window'。您将在以下章节中了解更多信息。因此,如果以下内容不能立即理解也没关系:在TypeScript4.2之前,类型别名可能会出现在错误消息中,有时会替代等效的匿名类型(可能不是故意的)。接口名称将始终出现在错误消息中。类型别名可能无法实现声明合并,但接口可以。接口只能用于声明对象的形状。原始类型不能重命名。当按名称使用接口时,它们的名称将始终出现在错误消息中。如果直接Use,大部分时候会出现原来的结构,大家可以根据个人喜好选择。TypeScript会告诉您是否需要声明其他内容。如果您喜欢探索性使用,请在需要使用该类型的功能之前使用接口。类型断言有时,您知道值的类型,但TypeScript不知道。例如,如果您使用document.getElementById,TypeScript只知道它会返回一个HTMLElement,但您知道您要获取的是一个HTMLCanvasElement。此时,您可以使用类型断言将其指定为更具体的类型:constmyCanvas=document.getElementById("main_canvas")asHTMLCanvasElement;就像类型注释一样,类型断言也会被编译器移除,并且不会影响任何运行时行为。您还可以使用尖括号语法(注意它不能在.tsx文件中使用),这是等效的:constmyCanvas=document.getElementById("main_canvas");记住:因为类型断言会在编译时被移除,所以在运行时不会进行类型断言检查,即使类型断言错误也不会产生异常或null。TypeScript只允许类型断言转换为或多或少特定的类型。这条规则可以防止一些不可能的强制类型转换,例如:constx="hello"asnumber;//类型'string'到类型'number'的转换可能是错误的,因为这两种类型都没有足够的重叠。如果这是故意的,请先将表达式转换为“未知”。有时,此规则可能显得非常保守,使您无法有效地转换类型。如果发生这种情况,您可以使用双重断言,首先断言为任何(或未知),然后断言为所需的类型:consta=(exprasany)asT;LiteralTypes除了常见的字符串和数字类型,我们还可以将类型声明为更具体的数字或字符串。众所周知,在JavaScript中有几种声明变量的方法。比如var和let,这种方式声明的变量后面可以修改,而const,这种方式声明的变量不能修改,这会影响TypeScript为字面量创建类型。letchangingString="HelloWorld";changingString="OláMundo";//因为`changingString`可以表示任何可能的字符串,//这就是TypeScript在类型系统中描述它的方式changingString;//letchangingString:stringconstconstantString="HelloWorld";//因为`constantString`只能表示1种可能的字符串,所以它//有一个字面量类型representationconstantString;//constconstantString:"HelloWorld"字面量类型本身不是很有用:letx:"hello"="hello";//OKx="hello";//...x="howdy";//类型'"howdy"'不可分配给类型'"hello"'。它似乎更有用。例如,当函数只能传入一些固定的字符串时:functionprintText(s:string,alignment:"left"|"right"|"center"){//...}printText("Hello,world","left");printText("G'day,mate","centre");//''centre''类型的参数不能分配给'"left"类型的参数|“正确”|“中心”'。数字文字类型也是一样的:functioncompare(a:string,b:string):-1|0|1{返回一个===b?0:a>b?1:-1;}当然,你也可以结合非文字类型:interfaceOptions{width:number;}functionconfigure(x:Options|"auto"){//...}configure({width:100});configure("auto");configure("automatic");//''automatic''类型的参数不能分配给'Options|“汽车”'。还有一种文字类型,布尔文字。由于只有两种布尔文字类型,true和false,类型boolean实际上是联合类型true|的别名。错误的。字面推断当您将变量初始化为对象时,TypeScript假定该对象的属性值将在未来被修改。例如,如果你这样写代码:constobj={counter:0};if(someCondition){obj.counter=1;}TypeScript之前不认为obj.counter是0,现在是错误的赋值为1。也就是说obj.counter必须是string类型,但不一定是0,因为类型可以决定读写行为。这同样适用于字符串:declarefunctionhandleRequest(url:string,method:"GET"|"POST"):void;constreq={url:"https://example.com",method:"GET"};handleRequest(req.url,req.method);//'string'类型的参数不能分配给'“获取”|“邮政”'。在上面的例子中,req.method被推断为字符串而不是“GET”,因为在创建req和调用handleRequest函数之间,可能还有其他代码,也许将req.method分配给一个新的字符串,例如“Guess”。所以TypeScript报错了。解决方法有两种:添加类型断言改变推理结果://改变1:constreq={url:"https://example.com",method:"GET"as"GET"};//改变2handleRequest(req.url,req.methodas"GET");修改1的意思是“我有意将req.method的类型设为文字类型“GET”,这将防止将来可能对字段的赋值,例如“GUESS”。”修改2表示“我知道req.method的值是“GET””。您还可以使用asconst将整个对象转换为类型文字:constreq={url:"https://example.com",method:"GET"}asconst;handleRequest(req.url,req.method);asconst作用类似于const,但是对于类型系统来说,它可以保证所有的属性都被赋予一个字面量类型,而不是一个更通用的类型,比如string或者number。null和undefinedJavaScript有两个原始值代表空或未初始化,它们分别是null和undefined。TypeScript有两个对应的同名类型。它们的行为取决于是否打开了strictNullChecks选项。strictNullChecksoff当strictNullChecks选项关闭时,如果一个值可能为null或未定义,它仍然可以被正确访问,或分配给任何类型的属性。这有点类似于没有空检查的语言(像C#、Java)。缺少这些检查是错误的主要来源,因此我们始终建议开发人员启用strictNullChecks选项。strictNullChecks开启当开启strictNullChecks选项时,如果一个值可能为null或undefined,则需要在使用它的方法或属性之前检查这些值,就像在使用可选属性之前检查它是否为undefined一样,我们可以还可以使用类型缩小来检查值是否为空:());}}Non-nullAssertionOperator(suffix!)(非空断言运算符)TypeScript提供了一种特殊的语法,可以在不做任何检查和未定义的情况下从类型中删除null,这就是写!在任何表达式之后,这是一个有效的类型断言,表明它的值不能为null或未定义:functionliveDangerously(x?:number|null){//没有错误控制台。log(x!.toFixed());}与其他类型断言一样,这也不会改变任何运行时行为。重要的是,只使用!当您确定该值不能为null或undefined时。枚举(Enums)枚举是TypeScript新增的一个特性,用来描述一个值可能是多个常量中的一个。与大多数TypeScript功能不同,这不是类型级别的增量,而是对语言和运行时的补充。因此,您应该了解此功能。但是你可以等到你用到它,除非你真的想用它。您可以在枚举类型页面上了解更多信息。不太常见的原语让我们来谈谈JavaScript中剩下的一些原语类型。但我们不会深入。bigIntES2020引入了原始类型BigInt来表示非常大的整数://CreatingabigintviatheBigIntfunctionconstoneHundred:bigint=BigInt(100);//通过文字语法创建BigIntconstanotherHundred:bigint=100n;在TypeScript3.2发行说明中了解更多信息。Symbol也是JavaScript中的原始类型。通过函数Symbol(),我们可以创建一个全局唯一的引用:constfirstName=Symbol("name");constsecondName=Symbol("名称");if(firstName===secondName){//此条件将始终返回“false”,因为类型“typeoffirstName”和“typeofsecondName”没有重叠。//永远不会发生}您可以在符号页面上阅读更多相关信息。TypeScript系列TypeScript系列文章由官方文档翻译、重点难点解析、实战技巧三部分组成,内容涵盖入门、进阶、实战。旨在为您提供系统的TS学习教程。整个系列预计约有40篇文章。点此浏览全系列文章,建议顺便收藏本站。微信:“mqyqingfeng”,加我到世优唯一的读者群。如有错误或不准确的地方,请务必指正,万分感谢。如果你喜欢或者有启发,欢迎star,这也是对作者的鼓励。