TypeScript已经成为前端绕不开的基础。看完《深入理解TypeScript》,这篇总结中TypeScript解决的最关键的痛点是什么?类型约束,不确定情况下的提示,写代码阶段能知道自己的错误,是我认为最关键的三点。TypeScript能做的,JavaScript也能做,虽然用TS会写很多代码,但其实可以节省很多时间,因为你写的时候就知道哪里出了问题。我呼吁大家全面拥抱TypeScript。以后肯定需要从JavaScript项目中迁移TypeScript:假设:你懂JavaScript;知道如何在项目中使用常用方法和构建工具(如:webpack)。有了以上假设,从JavaScript迁移一般包括以下步骤:添加一个tsconfig.json文件;将文件扩展名从.js更改为.ts,开始使用any以减少错误;开始用TypeScript编写代码,尽可能减少any的使用;回到遗留代码,开始添加类型注释,并修复已识别的错误;为第三方JavaScript代码定义环境声明。请记住,所有JavaScript都是有效的TypeScript。这意味着,如果你要求TypeScript编译器在TypeScript中编译JavaScript代码,编译结果将与原始JavaScript代码完全相同。换句话说,将文件扩展名从.js更改为.ts不会造成任何负面影响。第三方代码你可以将你的JavaScript代码更改为TypeScript代码,但你无法让全世界都使用TypeScript。这就是TypeScript环境声明的用武之地。我们建议您先创建一个vendor.d.ts文件(.d.ts文件扩展名指定此文件是声明文件),然后我们可以向文件。或者,您可以创建特定于库的声明文件,例如jquery的jquery.d.ts。几乎前90%的JavaScript库的声明文件都存在像Def??initelyTyped这样的仓库中。在创建自己的定义声明文件之前,我们建议您在仓库中查找它们。虽然创建声明文件的快速而肮脏的方法是减少使用TypeScript的初始阻力的重要一步。考虑jquery的用例,您可以非常轻松快速地为它创建一个定义:declarevar$:any;有时,你可能想给一些变量一些明确的定义(例如:jquery),你会在类型中声明它,在空间中使用它。您可以使用type关键字快速实现此目的:declaretypeJQuery=any;declarevar$:JQuery;这为您提供了更清晰的使用模式。再一次,DefinitelyTyped中已经存在高质量的jquery.d.ts。现在您知道了如何在使用JavaScript第三方模块时克服JavaScript到TypeScript的阻力。接下来,我们将讨论环境声明。@types你可以通过npm安装@types,如下例所示,你可以为jquery添加一个声明文件:npminstall@types/jquery--save-dev@types支持全局和模块类型定义安装后,不需要特殊配置,可以像模块一样使用:import*as$from'jquery';variable例如,当你想告诉TypeScript编辑器process变量时,你可以这样做:declareletprocess:anyTIP你不需要为process这样做,因为这个已经存在于社区维护的node.d.ts允许你使用进程,并且可以成功通过TypeScript:process.exit();建议尽量使用接口,例如:interfaceProcess{exit(code?:number):void;}declareletprocess:Process;类实现接口:interfacePoint{x:number;y:number;}classMyPointimplementsPoint{x:number;y:数字;//同Point}Enumeration枚举是一种组织和收集关联变量的方式,其他语言都有,所以在TSenumCardSuit{Clubs,Diamonds,Hearts,Spades}中也加入了这个功能//简单的使用枚举TypeletCard=CardSuit.Clubs;//typesafeCard='notamemberofcardsuit';//错误:无法将字符串分配给`CardSuit`类型枚举Tristate{False,True,Unknown}编译成JavaScript:varTristate;(function(Tristate){Tristate[(Tristate['False']=0)]='假';三态[(三态['真']=1)]='真';三态[(三态['Unknown']=2)]='Unknown';})(Tristate||(Tristate={}));这意味着我们可以跨文件、模块拆分枚举定义~enumColor{Red,Green,Blue}enumColor{DarkRed=3,DarkGreen,DarkBlue}提示:您应该初始化枚举的延续块中的第一个成员,以便生成的代码不是先前定义的枚举类型值如果您定义初始值函数声明,TypeScript将警告您:typeLongHand={(a:number):number;};输入ShortHand=(a:number)=>number;可调用接口ReturnString{():字符串;箭头函数const简单:(foo:number)=>string=foo=>foo.toString();提示:它只能用作简单的箭头函数,不能使用重载。如果你想使用它,你必须使用完整的语法{(someArgs):someReturn}Instantiable:interfaceCallMeWithNewToGetString{new():string;}//usedeclareconstFoo:CallMeWithNewToGetString;constbar=newFoo();//bar被推断为string类型断言:建议只使用统一的asfoo语法,而不是的初始用法:letfoo:any;letbar=foo;//现在bar的类型是'string'但是,当您在JSX中使用断言语法时,这与JSX语法不明确:letfoo=bar;;因此,为了一致性,我们建议您使用asfoo的语法来断言类型断言和类型转换。它不被称为“类型转换”的原因是因为转换通常意味着某种运行时支持。然而,类型断言纯粹是一种编译时语法,同时,它是一种向编译器提供有关如何分析代码(甚至将其他代码粘贴和复制到您的项目中)的信息的方式,但是,您应该谨慎使用断言。我们以原始代码为例,如果您不按照约定添加属性,TypeScript编译器不会警告您:interfaceFoo{bar:number;bas:string;}constfoo={}asFoo;//啊,忘了什么?上面的foo没有bar和bas属性,但是它通过了测试。这是相当危险的,熟悉的xxfromundefinederrordoubleassertion类型的断言,虽然我们已经证明它不是那么安全,但是它还是有用的。如以下非常实际的示例所示,当用户知道传入参数的更具体类型时,类型断言按预期工作:functionhandler(event:Event){constmouseEvent=eventasMouseEvent;}但是,在下面示例将报告错误,即使用户使用了类型断言:functionhandler(event:Event){constelement=eventasHTMLElement;//错误:'Event'和'HTMLElement'都不能分配给另一个a}如果您仍想使用该类型,则可以使用双断言。首先断言兼容any的所有类型,编译器不会报错:functionhandler(event:Event){constelement=(eventasany)asHTMLElement;//ok}TypeScript如何判断单次断言是否足够S类型是类型T的子集,或者类型T是类型S的子集,S可以成功断言为T。这样做是为了额外的安全性类型断言,完全没有根据的断言是危险的,如果你想这样做,你可以使用任何。新鲜度为了让检查对象字面量类型变得更容易,TypeScript提供了“新鲜度”(也称为更严格的对象字面量检查)的概念,以确保对象字面量在结构上是类型兼容的。结构类型非常方便。考虑以下示例代码,它允许您非常方便地从JavaScript迁移到TypeScript,并将提供类型安全:functionlogName(something:{name:string}){console.log(something.name);}constperson={姓名:'马特',工作:'很棒'};constanimal={name:'cow',diet:'素食主义者,但有自己的牛奶'};constrandow={注意:`我没有name属性`};logName(person);//oklogName(动物);//oklogName(随机);//错误:没有`name`属性但是,结构类型有一个缺点,它可能会误导您认为收到的数据比实际接收的数据多。例如,TypeScript发出错误警告:functionlogName(something:{name:string}){console.log(something.name);}logName({name:'matt'});//oklogName({name:'matt'',job:'beingawesome'});//错误:对象字面量只能指定已知属性,此处不存在`job`属性。警告请注意,此错误消息仅发生在对象文字上不允许的属性:类型可以包含索引签名以明确可以使用其他属性:letx:{foo:number,[x:string]:any};x={foo:1,baz:2};//ok,'baz'属性匹配React中的索引签名readonly/你可以放心,没有人会这样做。this.props.foo=123;//错误:道具是不可变的this.state.baz=456;//错误:你应该使用this.setState()}}泛型//创建一个泛型类classQueue{privatedata:T[]=[];push=(item:T)=>this.data.push(item);弹出=():T|undefined=>this.data.shift();}//简单使用constqueue=newQueue();queue.push(0);queue.push('1');//Error:Cannotpusha`string`,onlynumbertypeisallowed你可以随意调用泛型参数,当你使用简单的泛型时,泛型通常用T、U、V来表示。如果你有不止一种泛型在你的参数中,你应该使用一个更语义化的名字,比如TKey和TValue(通常,以T作为泛型类型的前缀,在其他语言如C++中,也称为Template)VariantsVariants是一个简单而重要的在类型兼容性方面需要理解的概念。对于简单类型Base和Child,如果Child是Base的子类,则可以将Child的实例分配给Base类型的变量。Nevernever类型是TypeScript中的基础类型。它自然分配的一些示例:从不返回值的函数(例如,如果函数包含while(true){});一个总是抛出错误的函数(例如functionfoo(){thrownewError('NotImplemented')},foo的返回类型是never)你也可以将它用作类型注释:letfoo:never;//ok但是,never类型只能赋值给另一个never:letfoo:never=123;//错误:数字类型不能分配给never类型//好的,neverlet作为函数返回类型;})();与void的区别一旦有人告诉你,never表示一个永远不会优雅返回的函数,你可能马上会想到类似这样的void,但实际上,void表示没有类型,never表示一个永远不会返回的值的类型存在。当一个函数没有返回值时,它返回一个void类型,但是当一个函数根本没有返回值(或者总是抛出错误)时,它返回一个never,void指的是一个可以赋值的类型(在strictNullChecking是假的),但永远不能分配给任何其他类型,除了永远不会TypeScript索引签名JavaScript会在对象类型的索引签名上隐式调用toString方法,而在TypeScript中,为了防止初学者受伤(我总是在stackoverflow上看到很多JavaScript用户这样做。),它会抛出错误。constobj={toString(){返回'你好';}};constfoo:any={};//错误:索引签名必须是字符串、数字....foo[obj]='World';//FIX:TypeScript强制你明确地这样做:foo[obj.toString()]='世界';声明一个索引签名我们使用any来让TypeScript允许我们做任何我们想做的事情。事实上,我们可以显式指定索引签名。例如:假设你想确认对象中存储的所有内容都符合{message:string}的结构,你可以通过[index:string]:{message:string}来实现。constfoo:{[index:string]:{message:string};}={};//存储的东西必须符合结构//okfoo['a']={message:'somemessage'};//Error,mustcontain`message`foo['a']={messages:'somemessage'};//读取时也会有类型检查//okfoo['a'].message;//Error:messages中没有foo['a'].messages;TIP索引签名中的名称(例如:indexin{[index:string]:{message:string}})除了可读性之外没有其他意义。例如:如果有用户名,可以使用{username:string}:{message:string},这样有助于下一个开发者看懂你的代码。声明索引签名时,所有显式成员都必须符合索引签名://okinterfaceFoo{[key:string]:number;x:数字;y:数字;}//错误接口栏{[key:string]:number;x:数字;y:字符串;//Error:yattributemustbeoftypenumber}至此4000字简单介绍了TypeScript的基本内容。当然,这里的每个部分都可以展开很长时间。大家需要仔细阅读下一章《深入理解TypeScript》,TypeScript原理、工程环境等进阶写作~写在最后:觉得写的不错,欢迎关注微信公众号:前端巅峰回复:进群就进多多多小姐姐的前端大交流群~