typescript 2 : custom typings for untyped npm module

标签 typescript npm typescript-typings

尝试在 other places 中发布的建议后,我发现自己无法运行使用无类型 NPM 模块的 typescript 项目。下面是一个最小的例子和我尝试过的步骤。

对于这个最小的例子,我们假设 lodash没有现有的类型定义。因此,我们将忽略包 @types/lodash并尝试手动添加其打字文件 lodash.d.ts到我们的项目。

文件夹结构

  • 节点模块
  • 洛达什
  • 源文件
  • 脚.ts
  • 打字
  • 定制
  • lodash.d.ts
  • 全局
  • index.d.ts
  • package.json
  • tsconfig.json
  • typings.json

  • 接下来是文件。

    文件 foo.ts
    ///<reference path="../typings/custom/lodash.d.ts" />
    import * as lodash from 'lodash';
    
    console.log('Weeee');
    

    文件 lodash.d.ts直接复制原版@types/lodash包。

    文件 index.d.ts
    /// <reference path="custom/lodash.d.ts" />
    /// <reference path="globals/lodash/index.d.ts" />
    

    文件 package.json
    {
      "name": "ts",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "typings": "./typings/index.d.ts",
      "dependencies": {
        "lodash": "^4.16.4"
      },
      "author": "",
      "license": "ISC"
    }
    

    文件 tsconfig.json
    {
      "compilerOptions": {
        "target": "ES6",
        "jsx": "react",
        "module": "commonjs",
        "sourceMap": true,
        "noImplicitAny": true,
        "experimentalDecorators": true,
        "typeRoots" : ["./typings"],
        "types": ["lodash"]
      },
      "include": [
        "typings/**/*",
        "src/**/*"
      ],
      "exclude": [
        "node_modules",
        "**/*.spec.ts"
      ]
    }
    

    文件 typings.json
    {
        "name": "TestName",
        "version": false,
        "globalDependencies": {
            "lodash": "file:typings/custom/lodash.d.ts"
        }
    }
    

    如您所见,我尝试了许多不同的导入类型的方法:
  • 通过直接在 foo.ts 中导入它
  • 来自 typings房产在package.json
  • 通过使用 typeRootstsconfig.json带文件 typings/index.d.ts
  • 通过使用显式 typestsconfig.json
  • 通过包含 types目录在 tsconfig.json
  • 通过定制 typings.json文件和运行 typings install

  • 然而,当我运行 typescript 时:
    E:\temp\ts>tsc
    error TS2688: Cannot find type definition file for 'lodash'.
    

    我做错了什么?

    最佳答案

    不幸的是,这些东西目前没有很好的文档记录,但即使你能够让它工作,让我们回顾一下你的配置,以便你了解每个部分在做什么以及它如何与 typescript 处理和加载类型相关。

    首先让我们回顾一下您收到的错误:

    error TS2688: Cannot find type definition file for 'lodash'.
    

    这个错误实际上不是来自您的导入或引用,也不是您尝试在 ts 文件中的任何地方使用 lodash。相反,它来自对如何使用 typeRootstypes 属性的误解,所以让我们更详细地了解这些。

    关于 typeRoots:[]types:[] 属性的事情是它们是 而不是 加载任意声明( *.d.ts )文件的通用方法。

    这两个属性与新的 TS 2.0 特性直接相关,该特性允许从 NPM 包 打包和加载类型声明。

    理解这一点非常重要,这些仅适用于 NPM 格式的文件夹(即包含 package.json 或 index.d.ts 的文件夹)。
    typeRoots 的默认值是:
    {
       "typeRoots" : ["node_modules/@types"]
    }
    

    默认情况下,这意味着 typescript 将进入 node_modules/@types 文件夹并尝试加载它在那里找到的每个子文件夹作为 npm 包

    重要的是要了解,如果文件夹没有类似 npm 包的结构,这将失败。

    这就是您的情况发生的情况,也是您初始错误的根源。

    您已将 typeRoot 切换为:
    {
        "typeRoots" : ["./typings"]
    }
    

    这意味着 typescript 现在将扫描 ./typings 文件夹中的 子文件夹 并尝试将它找到的每个子文件夹加载为 npm 模块。

    因此,让我们假设您刚刚设置了 typeRoots 指向 ./typings 但还没有设置任何 types:[] 属性。您可能会看到以下错误:

    error TS2688: Cannot find type definition file for 'custom'.
    error TS2688: Cannot find type definition file for 'global'.
    

    这是因为 tsc 正在扫描您的 ./typings 文件夹并找到子文件夹 customglobal 。然后它试图将这些解释为 npm 包类型类型,但是这些文件夹中没有 index.d.tspackage.json,因此您会收到错误消息。

    现在让我们谈谈您正在设置的 types: ['lodash'] 属性。这有什么作用?默认情况下, typescript 将加载 typeRoots 中找到的所有 子文件夹。如果您指定 types: 属性,它只会加载那些特定的子文件夹。

    在您的情况下,您告诉它加载 ./typings/lodash 文件夹,但它不存在。这就是为什么你得到:

    error TS2688: Cannot find type definition file for 'lodash'
    

    所以让我们总结一下我们学到的东西。 Typescript 2.0 引入了 typeRootstypes 来加载打包在 npm 包中的声明文件。如果您有自定义类型或单个松散的 d.ts 文件,这些文件不包含在遵循 npm 包约定的文件夹中,那么这两个新属性不是您想要使用的。 Typescript 2.0 并没有真正改变它们的使用方式。您只需要以多种标准方式之一将这些文件包含在您的编译上下文中:
  • 直接将其包含在 .ts 文件中:///<reference path="../typings/custom/lodash.d.ts" />
  • 在您的 ./typings/custom/lodash.d.ts 属性中包含 files: []
  • ./typings/index.d.ts 属性中包含 files: [](然后递归地包含其他类型。
  • ./typings/** 添加到您的 includes:

  • 我们希望,在此基础上讨论,你就可以告诉为什么改变你疯了你tsconfig.json让事情再次合作。

    编辑:

    我忘记提及的一件事是 typeRootstypes 属性实际上只对 自动 全局声明的加载有用。

    例如,如果你

    npm install @types/jquery
    

    并且您正在使用默认的 tsconfig,然后该 jquery 类型包将自动加载并且 $ 将在您的所有脚本中可用,而无需执行任何进一步的 ///<reference/>importtypeRoots:[] 属性旨在添加额外的位置,从那里自动加载类型包。
    types:[] 属性的主要用例是禁用自动加载行为(通过将其设置为空数组),然后仅列出要全局包含的特定类型。

    从各种 typeRoots 加载类型包的另一种方法是使用新的 ///<reference types="jquery" /> 指令。注意 types 而不是 path 。同样,这仅对全局声明文件有用,通常是那些不执行 import/export 的文件。

    现在,这是导致与 typeRoots 混淆的一件事。记住,我说过 typeRoots 是关于模块的全局包含。但是 @types/folder 也参与标准模块解析(无论您的 typeRoots 设置如何)。

    具体来说,显式导入模块总是会绕过所有 includesexcludesfilestypeRootstypes 选项。所以当你这样做时:

    import {MyType} from 'my-module';
    

    上面提到的所有属性都被完全忽略了。 模块解析 期间的相关属性是 baseUrlpathsmoduleResolution

    基本上,当使用 node 模块解析时,它将开始搜索文件名 my-module.tsmy-module.tsxmy-module.d.ts ,从您的 baseUrl 配置指向的文件夹开始。

    如果它没有找到文件,那么它会寻找一个名为 my-module 的文件夹,然后搜索一个带有 package.json 属性的 typings,如果里面有 package.json 或没有 typings 属性告诉它要加载哪个文件,然后搜索 index.ts/tsx/d.ts在那个文件夹内。

    如果仍然不成功,它将在 node_modules 文件夹中从您的 baseUrl/node_modules 开始搜索这些相同的内容。

    此外,如果没有找到这些,它将搜索 baseUrl/node_modules/@types 以查找所有相同的内容。

    如果它仍然没有找到任何东西,它将开始转到父目录并在那里搜索 node_modulesnode_modules/@types。它将继续向上目录,直到它到达您的文件系统的根目录(甚至在您的项目之外获取节点模块)。

    我想强调的一件事是模块解析完全忽略您设置的任何 typeRoots。因此,如果您配置了 typeRoots: ["./my-types"] ,则在显式模块解析期间不会搜索到它。它仅用作一个文件夹,您可以在其中放置要提供给整个应用程序的全局定义文件,而无需进一步导入或引用。

    最后,您可以使用路径映射(即 paths 属性)覆盖模块行为。例如,我提到在尝试解析模块时不会咨询任何自定义 typeRoots。但是如果你喜欢你可以让这种行为发生:
    "paths" :{
         "*": ["my-custom-types/*", "*"]
     }
    

    这样做是针对与左侧匹配的所有导入,尝试在尝试包含它之前修改右侧的导入(右侧的 * 表示您的初始导入字符串。例如,如果您导入:

    import {MyType} from 'my-types';
    

    它会首先尝试导入,就像你写的一样:

    import {MyType} from 'my-custom-types/my-types'
    

    然后如果它没有找到它会在没有前缀的情况下再次尝试(数组中的第二项只是 * ,这意味着初始导入。

    因此,通过这种方式,您可以添加其他文件夹来搜索自定义声明文件,甚至是您希望能够 .ts 的自定义 import 模块。

    您还可以为特定模块创建自定义映射:
    "paths" :{
       "*": ["my-types", "some/custom/folder/location/my-awesome-types-file"]
     }
    

    这会让你做

    import {MyType} from 'my-types';
    

    但是然后从 some/custom/folder/location/my-awesome-types-file.d.ts 读取这些类型

    关于 typescript 2 : custom typings for untyped npm module,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40222162/

    相关文章:

    javascript - 将应用程序表达为 http.createServer 的参数

    javascript - typescript 对象在参数中休息打字

    typescript - 我可以指定一个属性也需要设置另一个属性吗?

    TypeScript 定义文件找不到 .d.ts

    npm - webpack-dev-server 不监视我的文件更改

    node.js - 将 CSV 转换为充满数字数组的 JSON 对象

    angularjs - 安装 angular 1.5 类型

    typescript - 我如何告诉 typescript 在 js 中逐字包含一行而不解析它

    javascript - 循环更改视频分辨率

    javascript - 无法从JavaScript访问Kotlin JS