当前位置: 首页 > 知识库问答 >
问题:

TypeScript 2:非类型化 npm 模块的自定义类型

薛寒
2023-03-14

在尝试在其他地方发布的建议后,我发现自己无法运行使用非类型化 NPM 模块的打字稿项目。下面是一个最小示例和我尝试过的步骤。

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

文件夹结构

    < li >节点模块 < ul > < li>lodash
    < li>foo.ts
  • 自定义
    • 洛达什.d.ts

    接下来是文件。

    文件foo.ts

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

    文件lodash.d.ts直接从原始@类型/洛达什包中复制。

    文件索引.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"
      ]
    }
    

    File typings.json

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

    如您所见,我尝试了许多不同的输入方式:

    1. 通过直接导入到foo.ts
    2. 通过package.json
    3. 中的 类型属性
    4. 通过在tsconfig.json中使用typeRoots和文件typings/index.d.ts
    5. 通过在tsconfig.json
    6. 中使用显式 类型
    7. 通过在tsconfig.json
    8. 中包含 类型目录
    9. 通过创建自定义typings.json文件并运行类型安装

    然而,当我运行打字稿时:

    E:\temp\ts>tsc
    error TS2688: Cannot find type definition file for 'lodash'.
    

    我到底做错了什么?

共有3个答案

司马宏茂
2023-03-14

“*”: [“./types/*”]tsconfig 路径中的这一行在 2 小时挣扎后修复了所有内容。

{
  "compilerOptions": {
    "moduleResolution": "node",
    "strict": true,
    "baseUrl": ".",
    "paths": {
      "*": ["./types/*"]
    },
    "jsx": "react",
    "types": ["node", "jest"]
  },
  "include": [
    "client/**/*",
    "packages/**/*"
  ],
  "exclude": [
    "node_modules/**/*"
  ]
}

types是文件夹名称,位于node_module旁边,即在客户端文件夹(或src文件夹)级别中< code > types/third-party-lib/index . d . ts < br > index . d . ts具有< code > declare module ' third-party-lib ';

注意:上面的配置是一个不完整的配置,只是为了了解它的类型、路径、包含和排除的外观。

袁俊弼
2023-03-14

编辑:过时。阅读上面的答案。

我仍然不明白这一点,但我找到了一个解决方案。使用以下tsconfig.json

{
  "compilerOptions": {
    "target": "ES6",
    "jsx": "react",
    "module": "commonjs",
    "sourceMap": true,
    "noImplicitAny": true,
    "experimentalDecorators": true,
    "baseUrl": ".",
    "paths": {
      "*": [
        "./typings/*"
      ]
    }
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

删除typings.json和文件夹类型下的所有内容,除了lodash.d.ts。还删除所有//…引用

窦宏旷
2023-03-14

不幸的是,这些事情目前还没有很好地记录下来,但即使您能够让它工作,让我们检查一下您的配置,以便您了解每个部分正在做什么,以及它如何与typescript处理和加载类型相关联。

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

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

这个错误实际上不是来自于您的导入或引用,或者您试图在ts文件中的任何位置使用lodash。相反,它来自于对如何使用typeRoots类型properties的误解,所以让我们更详细地了解一下。

typeRoots:[]type:[]属性的问题在于它们不是加载任意声明(*.d.ts)文件的通用方法。

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

理解这一点非常重要,即这些仅适用于NPM格式的文件夹(即包含package.json或index.d.ts的文件夹)。

< code>typeRoots的默认值是:

{
   "typeRoots" : ["node_modules/@types"]
}

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

如果文件夹没有类似npm包的结构,这将会失败,理解这一点很重要。

这就是在你的案例中发生的事情,也是你最初错误的根源。

您已将typeRoot切换为:

{
    "typeRoots" : ["./typings"]
}

这就意味着,打字脚本现在将扫描./typings文件夹中的子文件夹,并尝试将其找到的每个子文件夹加载为npm模块。

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

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

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

现在让我们来谈谈您正在设置的类型:['

在您的情况下,您告诉它加载./typings/

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

所以让我们总结一下我们所学到的。Typecript 2.0引入了typeRoots类型,用于加载打包在npm包中的声明文件。如果您有自定义类型或单个松散的d.ts文件,这些文件不包含在遵循npm包约定的文件夹中,那么这两个新属性不是您想要使用的。Typecript 2.0并没有真正改变这些属性的使用方式。您只需要以多种标准方式之一将这些文件包含在编译上下文中:

>

  • 直接将其包含在<code>中。ts文件:///

    包括<代码>。/typings/custom/lodash . d . ts ,位于您的< code >文件:[]属性中。

    在你的文件中包括 ./typings/index.d.ts:[] 属性(然后递归地包含其他类型。

    正在添加<code>/在中键入/**包括:

    希望通过本次讨论,您能够知道为什么您对tsconfig进行了更改。json</code>让事情重新开始。

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

    例如,如果您

    npm install @types/jquery
    

    并且您正在使用默认的tsconfig,那么jquery类型包将被自动加载,并且< code>$将在您的所有脚本中可用,而无需执行任何进一步的< code>///

    typeRoots:[]属性用于添加其他位置,从这些位置自动加载类型包。

    < code>types:[]属性的主要用例是禁用自动加载行为(通过将其设置为空数组),然后只列出您希望全局包含的特定类型。

    从各种typeRoot加载类型包的另一种方法是使用新的///

    现在,这是导致与typeRoots混淆的事情之一。请记住,我说过typeRoots是关于模块的全球包含。但 @types/文件夹也涉及标准模块分辨率(无论您的 typeRoots 设置如何)。

    具体地说,显式导入模块总是绕过所有包括exclude文件>typeRootstypes选项。因此,当您这样做时:

    import {MyType} from 'my-module';
    

    上述所有属性都被完全忽略。模块解析过程中的相关属性为baseUrl路径 >。

    基本上,当使用<code>节点</code>模块解析时,它将开始搜索我的模块的文件名<code>。ts,我的模块。tsxmymodule.d.tsbaseUrl配置指向的文件夹。

    如果没有找到该文件,那么它将查找名为my-模块的文件夹,然后搜索带有typings属性的package.json,如果里面有package.json或没有typings属性,告诉它要加载哪个文件,那么它将在该文件夹中搜索index.ts/tsx/d.ts

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

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

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

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

    最后,您可以使用路径映射(即paths属性)覆盖模块行为。例如,我提到,在尝试解析模块时,不会咨询任何自定义typeRoots。但如果你喜欢,你可以这样做:

    "paths" :{
         "*": ["my-custom-types/*", "*"]
     }
    

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

    import {MyType} from 'my-types';
    

    它将首先尝试导入,就像您已经编写了:

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

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

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

    您还可以为特定模块创建自定义映射:

    "paths" :{
       "*": ["my-types", "some/custom/folder/location/my-awesome-types-file"]
     }
    

    这会让你做

    import {MyType} from 'my-types';
    

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

  •  类似资料:
    • Rust 自定义数据类型主要是通过下面这两个关键字来创建: struct: 定义一个结构体 enum: 定义一个枚举类型 而常量的创建可以通过 const 和 static 关键字来创建。

    • 存在多种方法来重新定义现有类型的行为以及提供新的类型。 重写类型编译 一个常见的需求是强制更改类型的“字符串”版本,即在create table语句或其他SQL函数(如cast)中呈现的版本。例如,应用程序可能希望强制呈现 BINARY 适用于除一个平台外的所有平台 BLOB 待渲染。在本例中,使用现有的泛型类型 LargeBinary ,是大多数用例的首选。但是为了更准确地控制类型,每个方言的编

    • 1. 包含头文件 #import <AdHubSDK/AdHubSDK.h> 2. AdHubCustomView 的创建和初始化 在需要导入广告的ViewController头文件中导入头文件并声明实例以及声明代理 #import <AdHubSDK/AdHubSDK.h> @interface AdHubCustomViewController ()<AdHubCustomViewDele

    • 以下代码不能按预期工作。显然,我不能在类定义中使用类自己的类型: 运行它的结果是: 此外,使用检查代码会返回: 如何将此代码更正为对Python和mypy有效?

    • 我在我的wordpress网站上创建了一个自定义帖子类型“Portfolio”,还为这个自定义帖子类型创建了一个类别部分,其中包含类别slug“PortCate”。 “Portfolio”帖子的永久链接如下: mysite.com/portfolio/post-name/ 但是类别url是 mysite.com/port-cate/category-slug/ 我的问题是:如何为这种帖子类型创建分

    • 但有些时候我们需要控制枚举的类型,那么我们可以 Enum 派生出自定义类来满足这种需要。通过修改上面的例子: #!/usr/bin/env python3 # -*- coding: UTF-8 -*- from enum import Enum, unique Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Au