预订“专业打字稿。开发可扩展的JavaScript应用程序”

图片任何使用动态类型语言的程序员都将证明,扩展代码的任务非常困难,并且需要大量的工程师。这就是Facebook,Google和Microsoft提出动态类型代码的静态类型的原因。



使用任何编程语言,我们都会跟踪异常并逐行读取代码以查找问题以及如何解决问题。 TypeScript使您可以自动化开发过程中令人沮丧的部分。



与许多其他类型的语言不同,TypeScript是面向应用程序的。它引入了新概念,使您可以更简洁,准确地表达想法,并轻松构建可扩展且安全的现代应用程序。



Boris Cherny帮助您了解TypeScript的所有细微差别和功能,并教您消除错误并扩展代码。



书籍结构



我(作者)试图为您提供有关TypeScript如何工作的理论理解,以及大量实用的编码建议。



TypeScript是一种实用的语言,因此理论和实践在本书中大多是相辅相成的,但是前两章主要介绍理论,最后只介绍了实践。



我们将介绍诸如编译器,类型检查器和类型本身之类的基础知识。接下来,我们讨论它们的种类和运算符,然后继续讨论高级主题,例如类型系统的细节,错误处理和异步编程。最后,我将向您展示如何在您喜欢的框架(前端和后端)中使用TypeScript,如何将现有的JavaScript项目迁移到TypeScript,并在生产环境中运行TypeScript应用程序。



大多数章节以一组练习结尾。自己尝试尝试以更好地掌握材料。他们的答案在这里



从JavaScript到TypeScript的分阶段迁移



TypeScript在设计时就考虑了JavaScript的互操作性。因此,尽管并非完全轻松,但迁移到TypeScript仍然是一种令人愉快的体验,使您可以一次转换代码库文件,获得更高级别的安全性并在提交后提交,并使您的老板和同事惊讶于静态键入代码的强大功能。 ...



在较高的级别上,代码库应该完全用TypeScript编写并进行强类型化,并且您依赖的第三方JavaScript库应具有良好的质量并具有自己的强类型。借助编译时错误捕获和丰富的TypeScript自动完成系统,编码过程将加倍。为了获得成功的迁移结果,将需要一些小步骤:



  • 将TSC添加到项目中。
  • 开始检查现有JavaScript代码的类型。
  • 将JavaScript代码逐文件移至TypeScript文件。
  • 安装依赖项的类型声明。也就是说,为不具有依赖关系的类型分配类型,或者为未类型的依赖关系编写类型声明,然后将其发送回DefinitelyTyped1。
  • 为代码库启用严格模式。


此过程可能需要一段时间,但是稍后您将立即看到安全性和性能方面的收益以及其他好处。让我们看一下列出的步骤。



步骤1:添加TSC



当使用结合了TypeScript和JavaScript的代码库时,首先让TSC编译tsconfig.json设置中的JavaScript文件和TypeScript文件:



{
     "compilerOptions": {
     "allowJs": true
}


仅此一项更改就可以使用TSC来编译JavaScript代码。只需将TSC添加到构建过程中,要么通过它运行每个JavaScript文件,要么通过构建过程继续运行旧版JavaScript文件,并通过TSC继续运行新的TypeScript文件。



将allowJs设置为true,TypeScript将不检查当前JavaScript代码中的类型,而是使用您请求的模块系统(在module字段中)将该代码转换为ES3,ES5或tsconfig.json文件中设置为目标的版本。 json文件)。第一步已经完成。提交并在背面轻拍一下-您的代码库现在正在使用TypeScript。



步骤2a:启用JavaScript类型检查(可选)



现在,TSC正在处理JavaScript,为什么不检查其类型?即使没有显式的类型注释,请记住TypeScript可以以与TypeScript代码相同的方式推断JavaScript代码的类型。在tsconfig.json中包含必需的选项:



{
     "compilerOptions": {
     "allowJs": true,
     "checkJs": true
}


现在,只要TypeScript编译JavaScript文件,它都会尝试以与对TypeScript代码相同的方式推断和验证类型。



如果您的代码库很大,并且在启用checkJs时立即遇到太多错误,请将其关闭。相反,可以通过添加// // ts-check指令(文件顶部的常规注释)来一次启用JavaScript文件检查。或者,如果大型文件引发了许多您还不想修复的错误,请启用checkJs并为这些文件添加// @ ts-nocheck指令。



TypeScript不能推断所有内容的类型(例如,它不能推断函数参数的类型),因此它将像JavaScript一样推断许多类型。如果您在tsconfig.json中启用了严格模式(推荐),那么您可能希望在迁移过程中允许隐式任何。将以下内容添加到tsconfig.json:



{
     "compilerOptions": {
     "allowJs": true,
     "checkJs": true,
     "noImplicitAny": false
}


将大部分代码迁移到TypeScript后,请记住再次打开noImplicitAny。这样做可能会发现许多遗漏的错误(除非您是Zenidar,这是JavaScript女巫Bavmorda的门徒,他可以用艾草药水检查一下自己的大脑力量)。


当TypeScript执行JavaScript代码时,它使用比TypeScript代码更软的推理算法。即:



  • 所有功能参数都是可选的。
  • 函数和类的属性类型根据使用情况来推断(而不是必须事先声明):



    class A {
        x = 0 // number | string | string[],    .
         method() {
                 this.x = 'foo'
         }
         otherMethod() {
                 this.x = ['array', 'of', 'strings']
         }
    
    }
  • 声明对象,类或函数后,可以为其分配其他属性。在后台,TypeScript通过为每个函数声明生成适当的名称空间并自动向每个对象文字添加索引签名来实现此目的。


步骤2b:添加JSDoc批注(可选)



您可能很着急,只需要为添加到旧JavaScript文件中的新功能添加一种类型注释即可。您可以使用JSDoc注释执行此操作,直到可以将此文件转换为TypeScript。



您可能之前已经看过JSDoc。这些是在代码顶部的注释,其注释以@开头,例如参数,@returns等。TypeScript理解JSDoc并将其与显式类型注释一起用作类型检查器的输入。



假设您有一个3000行服务文件(是的,我知道,您的“朋友”写了它)。您向其中添加一个新的服务功能:



export function toPascalCase(word) {
       return word.replace(
             /\w+/g,
             ([a, ...b]) => a.toUpperCase() + b.join('').toLowerCase()
       )
}


如果没有将utils.js完全转换为TypeScript,这肯定会发现很多错误,那么您只能注释toPascaleCase函数,从而在未类型化JavaScript的海洋中创建一小块安全之岛:



/**
     * @param word {string}    .
     * @returns {string}   PascalCase
     */
export function toPascalCase(word) {
     return word.replace(
           /\w+/g,
           ([a, ...b]) => a.toUpperCase() + b.join('').toLowerCase()
     )
}


没有此注释,JSDoc TypeScript会将toPascaleCase类型推断为(word:any)=>字符串。现在,在编译时,它将知道toPascaleCase的类型是(word:string)=> string。您会获得有用的文档。



有关JSDoc注释的更多信息,请访问TypeScript Wiki(https://github.com/Microsoft/TypeScript/wiki/JSDoc-support-in-JavaScript)。



步骤3:将文件重命名为.ts



将TSC添加到构建过程中并在可能的情况下开始有选择地开始类型检查和注释JavaScript代码之后,就该切换到TypeScript了。



逐个文件,将文件权限从.js(或.coffee,es6等)更新为.ts。在编辑器中重命名文件后,您将立即看到红色的波浪形朋友,指示类型错误,遗漏的大小写,忘记的空检查和变量名中的错别字。有两种删除方法。



  1. . , , , . checkJs, noImplicitAny tsconfig.json, any , , JavaScript .
  2. .ts tsconfig.json ( strict false), . any, . . , strict (noImplicitAny, noImplicitThis, strictNullChecks . .), . ( .)


, TODO any any, . , :



// globals.ts
type TODO_FROM_JS_TO_TS_MIGRATION = any

// MyMigratedUtil.ts
export function mergeWidgets(
       widget1: TODO_FROM_JS_TO_TS_MIGRATION,
       widget2: TODO_FROM_JS_TO_TS_MIGRATION
): number {
       // ...
}


两种方法都非常相关,由您决定哪种方法更可取。TypeScript是一种分步键入的语言,从头开始设计,可以以最安全的方式与未键入的JavaScript进行交互。与无类型的JavaScript或弱类型的TypeScript交互都没有关系,强类型的TypeScript将始终确保交互尽可能安全。



第4步:激活严谨性



一旦移植了关键数量的JavaScript代码,您将希望通过使用更严格的TSC标志一个接一个地使其一站式安全(有关标志的完整列表,请参阅附录E)。



完成后,您可以关闭负责与JavaScript交互的TSC标志,确认所有代码均以强类型TypeScript编写:



{
     "compilerOptions": {
     "allowJs": false,
     "checkJs": false
}


这将显示所有剩余的类型错误。对其进行修复,即可获得一个完美,安全的代码库,大多数OCaml的苛刻工程师都会为您提供支持。

执行以下步骤将有助于您将类型添加到所控制的JavaScript代码中。但是不受您控制的代码又如何呢?就像NPM上安装的一样。但是,在我们研究这个问题之前,让我们先讲一点...



查找JavaScript的类型



从TypeScript文件导入JavaScript文件时,TypeScript使用以下算法搜索其类型声明(请记住,在TypeScript中,“文件”和“模块”可互换使用):



  1. .d.ts , .js. .js.

    , :



    my-app/

    ├──src/

    │ ├──index.ts

    │ └──legacy/

    │ ├──old-file.js

    │ └──old-file.d.ts



    old-file ( ) index.ts:



    // index.ts

    import './legacy/old-file'



    TypeScript src/legacy/old-file.d.ts ./legacy/old-file.
  2. , allowJs checkJs true, .js ( JSDoc) any.




TSC-: TYPEROOTS ( )



TypeScript node modules/@types , (../node modules/@types . .). .



, typeRoots tsconfig.json , . , TypeScript typings node modules/@types:



{
     "compilerOptions": {
            "typeRoots" : ["./typings", "./node modules/@types"]
     }
}


types tsconfig.json, , TypeScript . , , React:



{
     "compilerOptions": {
             "types" : ["react"]
     }
}




导入第三方JavaScript模块(您在节点模块中安装的NPM软件包)时,TypeScript使用略有不同的算法:



  1. 查找模块的本地类型声明,如果存在,则使用它。



    例如,你的目录结构如下所示:



    我的应用程序内/

    ├──node_modules/

    │└──foo/

    ├──src/

    │├──index.ts

    │└──types.d.ts



    这是type.d的样子.ts:



    // types.d.ts
    declare module 'foo' {
          let bar: {}
          export default bar
    }


    如果随后导入foo,则TypeScript使用type.d.ts中的外部模块声明作为其类型源:



    // index.ts

    从'foo'导入条
  2. package.json, . types typings, .d.ts, , .
  3. 否则它将在目录中循环查找节点模块/ @ types目录,其中包含模块的类型声明。



    例如,您安装了React:



    npm install react --save

    npm install @类型/ react --save-dev



    my-app /

    ├──node_modules/

    │├──@类型/

    ││└──react/

    │└──反应/

    ├──src/

    │└──index.ts



    导入时发生反应,打字稿会发现@类型/反应目录,并把它作为类型声明它的源代码:



    // index.ts

    导入*为阵营“反应”
  4. 否则,它将转到本地类型搜索算法的步骤1-3。


我列出了很多步骤,但是您会习惯它们。



关于作者



Boris Cherny是Facebook的首席工程师兼产品负责人。先前曾在VC,AdTech和多家初创公司工作,但如今大多数都不存在。他对编程语言,代码合成和静态分析感兴趣,并致力于与用户分享他在数字产品方面的经验。在他的空闲时间,他组织在旧金山打字稿俱乐部会议并维护个人博客- performancejs.com。您可以在github.com/bcherny上找到Boris的GitHub帐户



»有关这本书的更多详细信息,请参见出版商网站

»目录

»居住地摘录



优惠券25%的折扣-TypeScript



支付了纸质版本的书后,就会向该电子邮件发送一本电子书。



All Articles