【问题标题】:TypeScript: Using a plain JavaScript lib in web project, with custom typingsTypeScript:在 Web 项目中使用纯 JavaScript 库,并带有自定义类型
【发布时间】:2021-02-10 21:04:48
【问题描述】:

我有一个使用 TypeScript 和 Webpack 的网站项目。现在我需要在这个项目中使用一个外部专有的 JavaScript 库。这是我的项目结构:

├── dist
│   ├── foo.js
│   ├── main.js
│   └── index.html
├── src
│   ├── foo.d.ts
│   └── index.ts
├── webpack.config.js
└── tsconfig.json

文件dist/main.js由Webpack生成,使用ts-loader编译入口TypeScript文件src/index.tsfoo.jsmain.js 都在 dist/index.html 文件中引用,使用 html 脚本标记:

<script src="foo.js"></script>
<script src="main.js"></script>

dist/foo.js 库是一个普通的旧 JavaScript 文件,它不是 ES6 模块,它只是包含一堆类。

我创建了带有类型的foo.d.ts 文件,以帮助TypeScript 对foo.js 中定义的类的使用进行类型检查:

// src/foo.d.ts
export declare class MyClass {
  constructor(message: string);
}

但我无法正确注册它,以便 TypeScript 和 Webpack 都能正确处理此设置。问题在于 TypeScript 如何加载类型声明文件。如果我用相对路径引用它,TypeScript 可以看到并使用它,但 Webpack 抱怨它无法解析它:

这个 index.ts 编译,但是 Webpack 给出错误:

import { MyClass } from './foo';
const c = new MyClass('Hello, world!');

Webpack 错误:Module not found: Error: Can't resolve './foo' in '/path-to/src'

Webpack 失败的原因显然是它正在寻找foo 代码并没有找到它,因为编译后的JavaScript 包含require("./foo")

所以我需要替换这一行

import { MyClass } from './foo';

告诉 TypeScript 不要在编译的代码中包含这个 require() 调用。我认为this ts-loader discussion 中描述了这个问题,但我不确定那里的最终判决是什么。如果我这样导入

import { MyClass } from 'foo';

TypeScript 编译器给出错误Cannot find module 'foo' or its corresponding type declarations.。显然,必须在 tsconfig.json 中指定某些内容,以便 TypeScript 知道在哪里查找类型声明。但是添加"include": ["src/**/*"] 似乎并没有改变任何东西。

【问题讨论】:

    标签: javascript typescript webpack


    【解决方案1】:

    问题是你在谎报你是如何真正得到它的(嗯,不是真的,你只是不知道如何拼写“这存在于全球范围内”你的.d.ts 文件)。

    在运行时,你只是依赖MyClass 存在于你的作用域链上的某个地方,所以你需要告诉 TypeScript 你正在工作的环境就是那种环境。你这样做的方法是使用 modifies the global scope's type definition 的环境模块声明 - 这与你的定义非常相似,只是你不使用 export 关键字:

    // src/foo.d.ts
    // Note the lack of `export` here
    declare class MyClass {
      constructor(message: string);
    }
    

    或者,如果您使用window.MyClass,那么您使用a global declaration

    declare global {
      interface Window {
        MyClass: MyClass
      }
    }
    
    declare class MyClass {
      myMethod(): void
    }
    

    然后,在您的代码中,您只需 new MyClass("Hello world"),TypeScript 就会支持您。

    【讨论】:

    • 从全球 .d.ts 上的 TS 页面,我确认我的库就是这种情况。但我不介意我是否必须这样做import {MyClass} from 'foo',这将使我的全球范围受到更少的污染。您的建议(根本没有导入)的问题是 tsc 不加载类型定义。我刚收到Cannot find name 'MyClass' 错误。如何将 TS 指向 d.ts 文件,还是应该专门命名/放置它?
    • 我想你也需要配置typeRoots,或者baseUrl + include。见elfi-y.medium.com/typescript-ambient-module-8816c9e5d426
    猜你喜欢
    • 2020-10-03
    • 2017-06-21
    • 2016-11-12
    • 2020-08-08
    • 2019-04-01
    • 2021-01-19
    • 2018-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多