【问题标题】:error TS2306: '...index.d.ts' is not a module错误 TS2306:'...index.d.ts' 不是模块
【发布时间】:2017-01-09 14:28:45
【问题描述】:

我正在尝试在 Typescript 中编写一个我想在各种其他 typescript 或 JS 项目中使用的库。所有其他项目都在浏览器中运行。

我的 Typescript lib 项目有多个文件,每个文件都是一个 React 组件,有 1 个类和 1-2 个接口(组件 + 道具 + 状态,适合熟悉 React 的人)。

我希望我的组件库可以作为 AMD 模块被其他项目导入,并且我希望将所有已编译的 JS 代码捆绑在一个文件中,作为库构建过程的一部分。

到目前为止,我已经设法设置好所有内容,以便我的 lib 可以编译。我已经使用以下选项设置了编译器:jsx: "react", declaration: true, module: "amd"

为 lib 生成的代码如下所示:

define("epb-widget/WidgetItemNav", ["require", "exports", "react"], function (require, exports, React) {
    "use strict";
    exports.WidgetItemNav = ...;
});
define("epb-widget/WidgetItemInfo", ["require", "exports", "react"], function (require, exports, React) {
    "use strict";
    exports.WidgetItemInfo = ...;
});
define("epb-widget/WidgetItem", ["require", "exports", "react", "epb-widget/WidgetItemNav", "epb-widget/WidgetItemInfo"], function (require, exports, React, WidgetItemNav_1, WidgetItemInfo_1) {
    "use strict";
    exports.WidgetItem = ...;
});
define("epb-widget/WidgetOptions", ["require", "exports", "react"], function (require, exports, React) {
    "use strict";
    exports.WidgetOptions = ...;
});
define("epb-widget/Widget", ["require", "exports", "react", "epb-widget/WidgetItem", "epb-widget/WidgetOptions"], function (require, exports, React, WidgetItem_1, WidgetOptions_1) {
    "use strict";
    exports.Widget = ...;
});
define("epb-widget", ["require", "exports", "epb-widget/Widget", "epb-widget/WidgetItem", "epb-widget/WidgetItemInfo", "epb-widget/WidgetItemNav", "epb-widget/WidgetOptions"], function (require, exports, Widget_1, WidgetItem_2, WidgetItemInfo_2, WidgetItemNav_2, WidgetOptions_2) {
    "use strict";
    exports.Widget = Widget_1.Widget;
    exports.WidgetItem = WidgetItem_2.WidgetItem;
    exports.WidgetItemInfo = WidgetItemInfo_2.WidgetItemInfo;
    exports.WidgetItemNav = WidgetItemNav_2.WidgetItemNav;
    exports.WidgetOptions = WidgetOptions_2.WidgetOptions;
});

对于我来说,有很多 AMD 模块,但我可以接受。生成的代码看起来会很好用。

生成的.d.ts 文件如下所示:

declare module "epb-widget/WidgetItemNav" {
    import * as React from "react";
    export interface WidgetItemNavProps {
        ...
    }
    export class WidgetItemNav extends React.Component<WidgetItemNavProps, void> {
        ...
    }
}
declare module "epb-widget/WidgetItemInfo" {
    export interface WidgetItemInfoProps {
        ...
    }
    export const WidgetItemInfo: (props: WidgetItemInfoProps) => JSX.Element;
}
declare module "epb-widget/WidgetItem" {
    export interface WidgetItemProps {
        ...
    }
    export const WidgetItem: (props: WidgetItemProps) => JSX.Element;
}
declare module "epb-widget/WidgetOptions" {
    import * as React from "react";
    export interface WidgetOptionsProps {
        ...
    }
    export interface WidgetOptionsState {
        ...
    }
    export class WidgetOptions extends React.Component<WidgetOptionsProps, WidgetOptionsState> {
        ...
    }
}
declare module "epb-widget/Widget" {
    import * as React from "react";
    import { WidgetItemProps } from "epb-widget/WidgetItem";
    export interface WidgetProps {
        ...
    }
    export interface WidgetState {
        ...
    }
    export class Widget extends React.Component<WidgetProps, WidgetState> {
        ...
    }
}
declare module "epb-widget" {
    export { Widget, WidgetProps } from "epb-widget/Widget";
    export { WidgetItem, WidgetItemProps } from "epb-widget/WidgetItem";
    export { WidgetItemInfo, WidgetItemInfoProps } from "epb-widget/WidgetItemInfo";
    export { WidgetItemNav, WidgetItemNavProps } from "epb-widget/WidgetItemNav";
    export { WidgetOptions, WidgetOptionsProps } from "epb-widget/WidgetOptions";
}

再一次,这看起来很合理。这都是 Typescript 编译器直接输出的。

最后,这个库是一个 npm 模块,它的package.json 看起来像这样

{
  "name": "epb-widget",
  "version": "1.0.0",
  "description": "...",
  "main": "./dist/index.js",
  "typings": "./dist/index",
  "globalDependencies": {...},
  "devDependencies": {...}
}

但问题来了

当我尝试在我的一个项目中使用该库时,它实际上不起作用。

我只是尝试像这样导入类:

import {Widget, WidgetProps, WidgetItem} from "epb-widget";

但是打字稿编译器会抛出以下错误

 error TS2656: Exported external package typings file '.../node_modules/epb-widget/dist/index.d.ts' is not a module. Please contact the package author to update the package definition.

老实说,我不知道我应该在这里做什么。 index.d.ts 是由 tsc 生成的,我不确定为什么同样的 tsc 不能在另一个项目中使用它。

【问题讨论】:

  • 生成的 .d.ts 看起来像外部模块定义,这不是 'typings' 参数指向的定义文件所期望的。我用'commonjs'成功地做到了这一点;这是一个'amd'问题吗?如果您选择“commonjs”,您生成的 .d.ts 是什么样的?
  • 嗯,那我不应该在库的package.json 中使用“typings”参数吗?
  • 是的。我会这么认为。在依赖项目中,尝试使用生成的 .d.ts 作为外部类型文件,就像使用“纯”js 库一样
  • 是的,它有效。如果你想把你的评论变成一个实际的答案,我会赞成并接受它。感谢您的帮助。
  • 作为参考,您是否介意指出文档中提到通过项目中 typings 文件夹加载的类型定义与通过 typings 属性加载的类型定义之间存在差异的package.json。我真的没有在任何地方看到它。

标签: typescript amd typescript-typings


【解决方案1】:

这太长了,无法进入我们上面的讨论,但这里是我的 TL;DR 来创建一个库:

  • 创建一个 index.ts 以重新导出库中公开的定义,例如

    export * from './API'
    export * from './Decorators'
    ...
    
  • 使用--declaration 标志编译库文件以自动生成类型

  • package.json 添加一个typings 条目,指向生成的index.d.ts 文件

使用库:

  • 像任何其他库一样将其放入 node_modules 文件夹中
  • 只需import * as mylib from 'mylib':它会自动导入所有导出的定义类型

这个过程与commonjs 完美配合,据我所知,systemjs 也一样。我不知道amd,你生成的类型看起来和我的很不一样:

生成的index.d.ts 通常看起来像

export * from './API';
export * from './Decorators';
...

API.d.ts 文件通常看起来像

import * as stream from 'stream';
import * as net from 'net';
import * as url from 'url';
export interface Factory {
    end(): Promise<void>;
}
export interface ChannelFactory extends Factory {
    getChannel(name: string, closeListener?: () => void): Promise<Channel>;
    existsChannel(name: string): Promise<boolean>;
}
....

【讨论】:

  • 显然,问题在于只要您不将类型声明合并到一个文件中,它就可以正常工作(即:如果您使用--outDir,它可以工作,如果您使用--out它没有)。从我今天做的更多测试以及您提供的链接来看,正确打包所有内容的最佳方法似乎是对 TS 代码执行 2 次传递。第一遍生成打包到一个文件中的 JS 代码。第二遍将类型定义生成为单独的文件。然后每个人都很开心。
  • 很高兴知道! ...很高兴你有一个解决方案。
  • @LordOfThePigs 谢谢,4 年后它仍然有意义......
  • 5 年后仍然相关。我已经使用 webpack 生成了lib/index.js,并使用 TS 生成了类型定义。 TS 吐出单独的 .d.ts 文件,例如lib/src/Text.d.tslib/src/Title.d.ts。但是,如果我使用 --outFile 生成结合 Text.d.ts 和 Title.d.ts 的单个 lib/index.d.ts,则无法识别类型定义。有没有人设法解决这个问题?
  • 嘿@igor,这里也是。而且我需要使用 --outFile 因为它是 Bazel 目标并且它需要是单个文件。你能解决它吗?
猜你喜欢
  • 2019-04-18
  • 1970-01-01
  • 2019-08-31
  • 2018-11-10
  • 2020-02-23
  • 2018-12-07
  • 2016-11-10
  • 2020-01-18
  • 2022-12-16
相关资源
最近更新 更多