美文网首页
5.3 类型和类型声明

5.3 类型和类型声明

作者: 9e8aeff1c70c | 来源:发表于2021-05-25 08:15 被阅读0次

    Deno的设计原则之一是没有神奇的解决方案。当tyescript对文件进行类型检查时,它只关心文件的类型,而TSC编译器有很多逻辑来尝试解析这些类型。默认情况下,它需要带有扩展名的模棱两可的模块说明符,并尝试在.ts说明符下查找文件,然后是.d.ts,最后是.js(当模块解析设置为“node”时,再加上另一组完整的逻辑)。Deno处理显式说明符。

    不过,这可能会导致一些问题。例如,假设我想使用一个已经转换为JavaScript的类型脚本文件和一个类型定义文件。所以我有mod.js和mod.d.ts。如果我尝试将mod.js导入Deno,它将只执行我要求它做的事情,并导入mod.js,但这意味着我的代码将不会进行类型检查,就好像Tyescript正在考虑mod.d.ts文件而不是mod.js文件一样。

    为了在Deno中支持这一点,Deno有两个解决方案,其中有一个增强支持的解决方案的变体。您遇到的两种主要情况是:

    • 作为 JavaScript 模块的导入器,我知道应该将哪些类型应用于该模块。
    • 作为 JavaScript 模块的供应商,我知道应该将哪些类型应用于该模块。

    后一种情况更好,这意味着您作为模块的提供者或宿主,每个人都可以使用它,而不必弄清楚如何解析JavaScript模块的类型,但是当使用您可能无法直接控制的模块时,还需要能够执行前一种操作。

    导入时提供类型

    如果您正在使用JavaScript模块,并且您已经创建了类型(.d.ts文件)或以其他方式获得了要使用的类型,则可以使用@Deno-Types编译器提示指示Deno在进行类型检查时使用该文件,而不是JavaScript文件。@Deno-Types需要是单行双斜杠注释,使用该注释时会影响下一条导入或重新导出语句。

    例如,如果我有一个JavaScript模块CoolLib.js,并且我有一个想要使用的单独的CoolLib.d.ts文件,我会这样导入它:

    // @deno-types="./coolLib.d.ts"
    import * as coolLib from "./coolLib.js";
    

    当输入检查CoolLib及其在文件中的使用情况时,将使用CoolLib.d.ts类型,而不是查看JavaScript文件。

    编译器提示的模式匹配在某种程度上是宽容的,它将接受说明符的引号和非问号值,以及接受等号前后的空格。

    托管时提供类型

    如果您控制了模块的源代码,或者您控制了文件在Web服务器上的托管方式,则有两种方法可以通知Deno给定模块的类型,而不需要导入器执行任何特殊操作。

    使用三斜杠参考指令

    Deno支持使用三斜杠Reference指令,该指令采用TypeScript在TypeScript文件中使用的引用注释来包括其他文件,并将其应用于JavaScript文件。

    例如,如果我已经创建了CoolLib.js,并且在CoolLib.d.ts中为我的库创建了类型定义,那么我可以在CoolLib.js文件中执行以下操作:

    /// <reference path="./coolLib.d.ts" />
    // ... the rest of the JavaScript ...
    

    当Deno遇到此指令时,它将解析./CoolLib.d.ts文件,并在类型检查文件时使用该文件而不是JavaScript文件,但在运行程序时仍会加载JavaScript文件。

    使用 X-TypeScript-Types标题

    与三斜杠指令类似,Deno支持远程模块的标头,该标头指示Deno将给定模块的类型定位到哪里。例如,对https://example.com/coolLib.js的响应可能如下所示:

    HTTP/1.1 200 OK
    Content-Type: application/javascript; charset=UTF-8
    Content-Length: 648
    X-TypeScript-Types: ./coolLib.d.ts
    

    看到此标头时,Deno 会尝试在键入检查原始模块时检索并使用该标头。https://example.com/coolLib.d.ts

    要点

    类型声明语义

    类型声明文件(.d.ts文件)遵循与Deno中的其他文件相同的语义。这意味着假设声明文件是模块声明(UMD声明),而不是环境/全局声明。Deno将如何处理环境/全局声明是不可预测的。

    此外,如果类型声明导入其他内容,如另一个.d.ts文件,则其解析遵循Deno的正常导入规则。对于许多在Web上生成并可用的.d.ts文件,它们可能与Deno不兼容。

    为了克服这个问题,一些解决方案提供商,如Skypack CDN,将自动捆绑类型声明,就像它们提供作为ESM的JavaScript捆绑包一样。

    Deno 友好的CDNs

    有一些CDN托管与Deno很好集成的JavaScript模块。

    • Skypack.dev是一个CDN,当您将?dts作为查询字符串附加到远程模块导入语句时,它提供类型声明(通过X-tyescript-Types头)。例如:
    ```
    import React from "https://cdn.skypack.dev/react?dts";
    ```
    

    类型检查时JavaScript的行为

    如果在Deno中将JavaScript导入到TypeScript中,并且没有类型,即使您将checkJs设置为false(Deno的默认设置),TypeScript编译器仍将访问JavaScript模块并尝试对其进行一些静态分析,以至少尝试确定该模块的导出的形状,以验证TypeScript文件中的导入。

    在尝试导入“常规”ES模块时,这通常不是问题,但在某些情况下,如果模块有特殊包装,或者是全局UMD模块,则TypeScript对模块的分析可能会失败并导致误导性错误。在这种情况下,最好的做法是使用上面提到的方法之一提供某种形式的类型。

    Internals

    虽然不需要了解Deno的内部工作方式就能很好地利用Deno中的TypeScript,但它可以帮助理解它是如何工作的。

    在执行或编译任何代码之前,Deno通过解析根模块,然后检测其所有依赖项,然后递归地检索和解析这些模块,直到检索到所有依赖项,从而生成模块图。

    对于每个依赖项,都会使用两个潜在的“槽”。这里有代码槽和类型槽。在填充模块图时,如果模块是或可以发送到JavaScript,它将填充代码槽,并且仅类型依赖项(如.d.ts文件)将填充类型槽。

    构建模块图时,如果需要输入检查图形,Deno将启动TypeScript编译器,并将可能需要作为JavaScript发出的模块的名称提供给它。在此过程中,TypeScript编译器将请求额外的模块,Deno将查看依赖项的槽,如果它已填满,则在提供代码槽之前为其提供类型槽。

    这意味着,当您导入.d.ts模块,或者使用上面的解决方案之一为JavaScript代码提供替代类型模块时,解析该模块时将提供给TypeScript。

    相关文章

      网友评论

          本文标题:5.3 类型和类型声明

          本文链接:https://www.haomeiwen.com/subject/wxlurltx.html