简体   繁体   English

TypeScript:在 web 项目中使用普通的 JavaScript 库,带有自定义类型

[英]TypeScript: Using a plain JavaScript lib in web project, with custom typings

I have a website project that uses TypeScript and Webpack.我有一个使用 TypeScript 和 Webpack 的网站项目。 Now I need to use an external proprietary JavaScript library in this project.现在我需要在这个项目中使用一个外部专有的 JavaScript 库。 This is my project structure:这是我的项目结构:

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

File dist/main.js is generated by Webpack that uses ts-loader to compile the entry TypeScript file src/index.ts .文件dist/main.js由 Webpack 生成,它使用ts-loader编译条目 TypeScript 文件src/index.ts Both foo.js and main.js are referenced in the dist/index.html file, using html script tag: foo.jsmain.js都在dist/index.html文件中被引用,使用 html 脚本标签:

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

The dist/foo.js library is a plain old JavaScript file, it is not an ES6 module, it just contains a bunch of classes. dist/foo.js库是一个普通的旧 JavaScript 文件,它不是 ES6 模块,它只是包含一堆类。

I have created the foo.d.ts file with typings to assist TypeScript in type-checking the use of the classes defined in foo.js :我创建了带有类型的foo.d.ts文件,以帮助 TypeScript 对foo.js中定义的类的使用进行类型检查:

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

But I have trouble registering it properly so that both TypeScript and Webpack deal with this setup properly.但是我无法正确注册它,以便 TypeScript 和 Webpack 都能正确处理此设置。 The problem lies in how TypeScript loads the type declarations file.问题在于 TypeScript 如何加载类型声明文件。 If I refer to it with relative path, TypeScript can see and use it, but Webpack complains that it cannot resolve it:如果我用相对路径引用它,TypeScript 可以看到并使用它,但 Webpack 抱怨它无法解决它:

This index.ts compiles, but Webpack gives error:index.ts编译,但 Webpack 给出错误:

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

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

The reason for Webpack failure apparently is that it is looking for the foo code and fails to find it, as the compiled JavaScript contains require("./foo") . Webpack 失败的原因显然是它正在寻找foo代码但未能找到它,因为编译后的 JavaScript 包含require("./foo")

So I need to replace this line所以我需要替换这条线

import { MyClass } from './foo';

with something that tells TypeScript not to include this require() call in the compiled code.告诉 TypeScript 不要在编译代码中包含这个require()调用。 I think this problem is described in this ts-loader discussion , but I am not sure what's the final verdict there.我认为这个ts-loader 讨论中描述了这个问题,但我不确定那里的最终判决是什么。 If I import like this如果我这样导入

import { MyClass } from 'foo';

the TypeScript compiler gives error Cannot find module 'foo' or its corresponding type declarations. TypeScript 编译器给出错误Cannot find module 'foo' or its corresponding type declarations. . . Apparently something has to be specified in tsconfig.json for TypeScript to know where to look for the type declarations.显然,必须在tsconfig.json中为 TypeScript 指定一些东西才能知道在哪里寻找类型声明。 But adding "include": ["src/**/*"] doesn't seem to change anything.但是添加"include": ["src/**/*"]似乎并没有改变任何东西。

The problem is that you're lying about how you're really getting it (well, not really, you just don't know how to spell "this exists in the global scope" in your .d.ts file).问题是你在谎报你是如何真正得到它的(嗯,不是真的,你只是不知道如何在你的.d.ts文件中拼写“这存在于全局范围内”)。

At runtime you're just relying on MyClass to exist somewhere up your scope chain, so you need to tell TypeScript that the environment you're working in is that kind of environment.在运行时,您只是依赖MyClass存在于 scope 链的某个位置,因此您需要告诉 TypeScript 您正在工作的环境就是这种环境。 The way you do that is with an ambient module declaration that modifies the global scope's type definition - which is very similar to your definition except you don't use the export keyword:您这样做的方式是使用修改全局范围的类型定义的环境模块声明 - 这与您的定义非常相似,只是您不使用export关键字:

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

Alternatively, if you're using window.MyClass , then you use a global declaration :或者,如果您使用window.MyClass ,则使用global声明

declare global {
  interface Window {
    MyClass: MyClass
  }
}

declare class MyClass {
  myMethod(): void
}

Then, in your code, you can just new MyClass("Hello world") and TypeScript will have your back.然后,在您的代码中,您只需new MyClass("Hello world")和 TypeScript 就会得到您的支持。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM