如何将其他类型导入到我的TypeScript自定义声明文件中?

时间:2017-01-27 14:47:56

标签: reactjs typescript jestjs typescript-typings enzyme

我有这个TypeScript + React + Webpack + Jest + Enzyme完全正常工作。

我认为需要在我的测试规范中访问一些全局功能。我可以通过将Jest配置中的setupTestFrameworkScriptFile选项指向.js文件来实现,我有类似这样的内容:

const Enzyme = require("enzyme");
const React = require("react");

const getMuiTheme = require("material-ui/styles/getMuiTheme").default;

global.mountWithContext = (node) => {
    return Enzyme.mount(node, {
        context: {
            muiTheme: getMuiTheme()
        },
        childContextTypes: {
            muiTheme: React.PropTypes.object
        }
    });
};

在我的spec文件中,我可以调用mountWithContext(),当我运行测试时它会正常工作。但我的编辑不承认这个功能。

要解决这个问题,我已经创建了一个/typings/declarations.d.ts文件:

declare function mountWithContext(node: any): any;

现在我的spec文件识别mountWithContext函数,但类型是"错误"。正确的定义更像是这样的:

declare function mountWithContext(node: React.ReactElement<any>): Enzyme.ReactWrapper<P, S>;

React.ReactElement已正确识别,因为@types/react/index.d.ts文件包含以下内容:

export = React;
export as namespace React;

对酶来说同样如此。没有导出全局Enzyme。看@types/enzyme/index.d.ts那里有这样的事情:

export interface ReactWrapper<P, S> extends CommonWrapper<P, S> {
    (...)
}

但即使我这样做:

declare function mountWithContext(node: React.ReactElement<any>): ReactWrapper<P, S>;

它不起作用。 ReactWrapper仍然无法识别。

我尝试在这个declarations.d.ts文件中导入,这将允许我正确使用该类型,但我的函数声明将停止在我的spec文件中被识别。我还尝试添加这样的三重斜杠指令:

/// <reference path="../node_modules/@types/enzyme/index.d.ts" />

该文件已被识别,但ReactWrapper类型仍然没有。

所以...我如何为我的自定义mountWithContext全局函数提供TypeScript函数声明,其中包含所有正确的类型,如下所示:

declare function mountWithContext(node: React.ReactElement<any>): ReactWrapper<P, S>;

2 个答案:

答案 0 :(得分:5)

如果我们要声明global.mountWithContext函数存在并且具有指示的类型,我们可以将以下内容添加到项目中的空声明文件中。

import React from 'react';
import enzyme from 'enzyme';

declare global {
  namespace NodeJS {
    interface Global {
      mountWithContext<P, S>(node: React.ReactElement<any>): enzyme.ReactWrapper<P, S>;
    }
  }
}

<强>详情

以下是上述每个结构的细分:

  1. declare global块:此构造的目的是通过引入新声明或修改现有声明来修改(如果愿意,扩充)全局范围,来自 非全局上下文,例如模块。我们的声明文件是一个模块,因为它包含从Enzyme导入import的顶级ReactWrapper子句。 这样的块被称为&#34;全局增强&#34;并且也可能出现在实现文件中。

  2. interface Global结构中包含的namespace NodeJS:在我们的测试中,我们作为全局变量的成员访问mountWithContext函数,偶然命名为global ,这是由Node环境提供的。此变量已由Node的类型声明声明,与其他环境全局变量(如process)处于同一级别。但是,我们需要通过添加新成员来扩充其类型。此全局global类型是已在interface Global内声明的namespace NodeJS,由Node的官方声明。我们通过声明interface Global的新成员来实现此目的。我们的扩充需要包含在包含namespace的{​​{1}}中,否则它将被视为单独的Global。粗略地说,词法范围适用。 (回想一下,TypeScript接口可以在同一范围内多次声明,并且这些声明将被合并)

  3. 备注

    我们在哪里发布此声明? 任何会导致TypeScript获取它并将其包含在我们的编译上下文中的地方。 按照惯例,我们将它放在项目根目录中名为 globals.d.ts 的文件中。 (从技术上讲,它可以被命名为其他东西并进入较低的目录。)

    请务必注意,此声明文件是我们的应用程序代码的一部分,应该检查到源代码管理中。 必须 与第三方声明一起放在 typings node_modules / @ types 等目录中,或者<强> jspm_packages / NPM / @类型

    同样重要的是要注意,此扩充仅影响TypeScript文件(interface.ts.tsx)。如果我们在使用TypeScript语言服务时声明这个函数只是为了在.d.ts.js文件中工作时提供智能感知,那么这种方法将不起作用。

答案 1 :(得分:0)

函数签名错误,您必须先声明泛型类型,例如:

function foo(T: bar): T // wrong
function foo<T>(T: bar): T // right
function foo<T extends K, K>(T: bar): K // right

在你的情况下,这样的事情应该有效:

declare function mountWithContext<P, S>(node: React.ReactElement<any>): ReactWrapper<P, S>;

如果您碰巧知道PS的内容,则可以使用<P extends React.Component, K>更具体,例如。