TypeScript和JavaScript近年来一直在稳步增长。我们在过去写代码的时候养成了一些习惯,有些习惯已经没有多大意义了。这里有10个我们都应该改掉的坏习惯。1.不使用严格模式(1)严格模式不写tsconfig.json这个习惯是什么样子的。{"compilerOptions":{"target":"ES2015","module":"commonjs"}}(2)开启严格模式即可:{"compilerOptions":{"target":"ES2015","module":"commonjs","strict":true}}(3)为什么会出现这种坏习惯在现有代码库中引入更严格的规则需要时间。(4)为什么不应该。更严格的规则使以后的代码维护更容易,为您节省大量时间。2.用||定义默认值(1)这个成语是什么样子的?使用旧的||处理fallbacks的默认值:functioncreateBlogPost(text:string,author:string,date?:Date){return{text:text,author:author,date:date||newDate()}}(2)如何使用新的??运算符,或重新定义参数中的默认值。functioncreateBlogPost(text:string,author:string,date:Date=newDate())return{text:text,author:author,date:date}}(3)为什么会有这样的坏习惯??运算符是去年才引入的,当在长函数中使用一个值时,很难将其设置为参数默认值。(4)为什么不应该?不同于||,??仅适用于null或undefined,不适用于所有虚假值。3.随意使用any类型(1)这个习惯是什么样子的当你不确定结构时,你可以使用any类型。asyncfunctionloadProducts():Promise{constresponse=awaitfetch('https://api.mysite.com/products')constproducts:any=awaitresponse.json()returnproducts}(2)Howshouldany一个地方whereany使用的是改为unknownasyncfunctionloadProducts():Promise{constresponse=awaitfetch('https://api.mysite.com/products')constproducts:unknown=awaitresponse.json()returnproductsasProduct[]}(3)为什么会有这种坏习惯?any很方便,因为它基本上禁用了所有类型检查。通常,any甚至用于官方提供的类型。例如,TypeScript团队在上例中将response.json()的类型设置为Promise。(4)为什么不应该做它基本上禁用了所有类型检查。通过any传入的任何内容都将完全放弃所有类型检查。这将使错误很难被捕获。4.valasSomeType(1)这个习语看起来像是在强行告诉编译器它无法推断的类型。asyncfunctionloadProducts():Promise{constresponse=awaitfetch('https://api.mysite.com/products')constproducts:unknown=awaitresponse.json()returnproductsasProduct[]}(2)这正是这个这就是TypeGuard的用武之地。functionisArrayOfProducts(obj:unknown):objisProduct[]{returnArray.isArray(obj)&&obj.every(isProduct)}functionisProduct(obj:unknown):objisProduct{returnobj!=null&&typeof(objasProduct).id==='string'}异步函数加载产品():Promise{constresponse=awaitfetch('https://api.mysite.com/products')constproducts:unknown=awaitresponse.json()if(!isArrayOfProducts(products)){thrownewTypeError('ReceivedmalformedproductsAPIresponse')}returnproducts}(3)为什么会出现这种坏习惯当从JavaScript迁移到TypeScript时,现有的代码库通常会对TypeScript编译器无法自动推断的类型做出假设。此时,通过asSomeOtherType可以加快转换速度,而无需修改tsconfig.xml中的设置。(4)为什么不应该做TypeGuard将确保所有检查都是明确的。5.Asany(1)intests这个习语看起来像在编写测试时创建了不完整的用例。interfaceUser{id:stringfirstName:stringlastName:stringemail:string}test('createEmailTextreturnstextthatgreatstheuserbyfirstname',()=>{constuser:User={firstName:'John'}asanyexpect(createEmailText(user)).toContain(user.firstName)}(2)如果您需要模拟测试数据,将模拟逻辑移动到要模拟的对象旁边并使其可重用,应该怎么办。John'lastName='Doe'email='john@doe.com'}test('createEmailTextreturnstextthatgreatstheuserbyfirstname',()=>{constuser=newMockUser()expect(createEmailText(user)).toContain(user.firstName)}(3)为什么会有这个坏习惯在为还没有广泛测试覆盖的代码编写测试时,往往会有复杂的大数据结构,但是对于要测试的具体功能只需要其中的一部分。不要关心其他的在短期属性。(4)为什么不应该这样做在某些情况下,被测代码取决于我们之前认为不重要的属性,然后需要更新该功能的所有测试。6.可选属性(1)这种习惯将属性标记为可选的,即使它们有时不存在,这是什么样子的。interfaceProduct{id:stringtype:'digital'|'physical'weightInKg?:numbersizeInMb?:number}(2)应该如何明确哪些组合存在,哪些不存在。interfaceProduct{id:stringtype:'digital'|'physical'}interfaceDigitalProducttextendsProduct{type:'digital'sizeInMb:number}interfacePhysicalProducttextendsProduct{type:'physical'weightInKg:number}(3)为什么会有这样的坏习惯,将属性标记为可选而不是拆分类型更容易并且产生更少的代码。它还需要对正在构建的产品有更深入的了解,并且如果对产品的设计进行了修改,则可能会限制代码的使用。(4)为什么不应该这样做类型系统最大的好处是可以在运行时用编译时检查来代替。更明确的类型可以在编译时检查可能未被注意到的错误,例如确保每个DigitalProduct都有一个sizeInMb。7、用一个字母传遍世界(1)这个成语长什么样子用一个字母命名泛型functionhead(arr:T[]):T|undefined{returnarr[0]}(2)应该如何提供完整的描述性类型名称。functionhead(arr:Element[]):Element|undefined{returnarr[0]}(3)为什么会有这样的坏习惯?在一个字母的名字中。它也可以更快地键入,只需键入字母T而不是写全名。(4)为什么不应该这样做泛型类型变量是变量,就像任何其他变量一样。当IDE开始向我们展示变量的类型细节时,我们已经慢慢放弃了通过名称描述变量类型的想法。例如,我们现在用constname='Daniel'而不是conststrName='Daniel'编写代码。同样,单字母变量名通常令人费解,因为不看声明就很难理解它们的含义。8、非布尔值的布尔检查(1)这个成语长什么样子?通过将值直接传递给if语句来检查值是否已定义。functioncreateNewMessagesResponse(countOfNewMessages?:number){if(countOfNewMessages){return`Youhave${countOfNewMessages}newmessages`}return'Error:Couldnotretrievenumberofnewmessages'}(2)如何显式检查我们关心的条件。functioncreateNewMessagesResponse(countOfNewMessages?:number){if(countOfNewMessages!==undefined){return`Youhave${countOfNewMessages}newmessages`}return'Error:Couldnotretrievenumberofnewmessages'}(3)为什么会有这么写短的坏习惯检测码?更简洁,让我们避免思考我们真正想要检测的是什么。(4)为什么不应该也许我们应该考虑一下我们实际检查的是什么。例如,上面的示例以不同方式处理countOfNewMessages为0的情况。9、“砰砰”运算符(1)这个成语把非布尔值转换成布尔值的样子是什么意思。functioncreateNewMessagesResponse(countOfNewMessages?:number){if(!!countOfNewMessages){return`Youhave${countOfNewMessages}newmessages`}return'Error:Couldnotretrievednumberofnewmessages'}(2)如何显式检查我们关心的条件。functioncreateNewMessagesResponse(countOfNewMessages?:number){if(countOfNewMessages!==undefined){return`Youhave${countOfNewMessages}newmessages`}return'Error:Couldnotretrievenumberofnewmessages'}(3)为什么有些人会有这样的坏习惯人们,明白!这就像进入JavaScript世界的一种仪式。它看起来简短而简洁,如果你很习惯它,你就会知道它的意思。这是将任意值转换为布尔值的便捷方法。特别是如果假值之间没有明确的语义边界,例如null、undefined和''。(4)为什么不应该这样做与许多编码便利一样,使用!!实际上混淆了代码的真正含义。这使得新开发人员很难理解代码,对于普通开发人员和JavaScript新手来说都是如此。引入细微的错误也很容易。对“非布尔类型的值”进行布尔检查时countOfNewMessages为0的问题在使用!!时仍然存在。10.!=null(1)这个成语看起来像牛逼运算符的小弟!=null允许我们检查null和undefined。functioncreateNewMessagesResponse(countOfNewMessages?:number){if(countOfNewMessages!=null){return`Youhave${countOfNewMessages}newmessages`}return'Error:Couldnotretrievenumberofnewmessages'}(2)如何显式检查我们关心的条件。functioncreateNewMessagesResponse(countOfNewMessages?:number){if(countOfNewMessages!==undefined){return`Youhave${countOfNewMessages}newmessages`}return'Error:Couldnotretrievenumberofnewmessages'(3)为什么你的代码是这样的坏习惯在null和undefined之间,然后!=null有助于简化对这两种可能性的检查。(4)为什么不应该这样做虽然null在早期的JavaScript中很麻烦,但当TypeScript处于严格模式时,它可以成为语言中无价的工具。一个常见的模式是将null值定义为不存在的值,将undefined定义为未知的值,例如user.firstName===null可能意味着用户实际上没有名字,而user.firstName===undefined只是意味着这意味着我们还没有询问用户(并且user.firstName===字面意思是''。