如何将其他类型导入我的 TypeScript 自定义声明文件?
How to import other types into my TypeScript custom declarations file?
我有这个 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
}
});
};
在我的规范文件上,我可以调用 mountWithContext()
,当我 运行 测试时它会工作得很好。但是我的编辑器不识别这个函数。
为了解决这个问题,我创建了一个 /typings/declarations.d.ts
文件:
declare function mountWithContext(node: any): any;
现在我的规范文件可以识别 mountWithContext
函数,但类型是 "wrong"。正确的定义应该是这样的:
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
文件中导入,这将允许我正确使用类型,但我的函数声明将不再在我的规范文件中被识别。我还尝试添加一个像这样的三斜线指令:
/// <reference path="../node_modules/@types/enzyme/index.d.ts" />
文件已被识别,但 ReactWrapper
类型仍未识别。
所以...我怎样才能为我的自定义 mountWithContext
全局函数创建一个 TypeScript 函数声明,其中包含所有正确的类型,如下所示:
declare function mountWithContext(node: React.ReactElement<any>): ReactWrapper<P, S>;
函数签名错误,必须先声明泛型,例如:
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>;
如果您碰巧知道 P
和 S
是什么,您可以更具体一些,例如使用 <P extends React.Component, K>
。
如果我们想声明 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>;
}
}
}
详情
下面是上面每个构造的分解:
declare global
块:这个构造的目的是修改,如果你愿意的话,扩大全局范围,通过引入新声明或修改现有声明,从 within 非全局上下文,例如模块。我们的声明文件是一个模块,因为它包含一个从 Enzyme 导入 ReactWrapper
的 top-level import
子句。
这样的块称为 "Global Augmentation",也可能出现在实现文件中。
interface Global
包裹在 namespace NodeJS
结构中:在我们的测试中,我们正在访问 mountWithContext
函数作为全局变量的成员,顺便说一下 global
,这是Node环境提供的。此变量已由 Node 的类型声明声明在与其他环境全局变量(例如 process
)相同的级别。但是,我们需要通过添加新成员来扩充其 type。这个全局global
的类型是官方已经在namespace
NodeJS
中声明的interface
Global
节点的声明。我们通过声明 interface
Global
的新成员来实现这一点。我们的扩充需要包含在包含 Global
的 namespace
中,否则它将被视为单独的 interface
。粗略地说,词法范围适用。 (回想一下,TypeScript 接口可以在同一范围内多次声明,并且这些声明将被合并)
备注
我们把这个声明放在哪里?
任何会导致 TypeScript 获取它并将其包含在我们的编译上下文中的地方。
按照惯例,我们将把它放在项目根目录中名为 globals.d.ts 的文件中。 (从技术上讲,它可以命名为其他名称并进入较低的目录)。
请务必注意,此声明文件是我们应用程序代码的一部分,应检入源代码管理。
它必须 not 与第三方声明一起放在 typings、 等目录中node_modules/@types,或jspm_packages/npm/@types.
同样重要的是要注意,此增强仅影响 TypeScript 文件(.ts
、.tsx
、.d.ts
)。如果我们宁愿声明此函数由 TypeScript 语言服务获取,只是为了在 .js
或 .jsx,
文件中工作时提供智能感知,则此方法将不起作用。
我有这个 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
}
});
};
在我的规范文件上,我可以调用 mountWithContext()
,当我 运行 测试时它会工作得很好。但是我的编辑器不识别这个函数。
为了解决这个问题,我创建了一个 /typings/declarations.d.ts
文件:
declare function mountWithContext(node: any): any;
现在我的规范文件可以识别 mountWithContext
函数,但类型是 "wrong"。正确的定义应该是这样的:
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
文件中导入,这将允许我正确使用类型,但我的函数声明将不再在我的规范文件中被识别。我还尝试添加一个像这样的三斜线指令:
/// <reference path="../node_modules/@types/enzyme/index.d.ts" />
文件已被识别,但 ReactWrapper
类型仍未识别。
所以...我怎样才能为我的自定义 mountWithContext
全局函数创建一个 TypeScript 函数声明,其中包含所有正确的类型,如下所示:
declare function mountWithContext(node: React.ReactElement<any>): ReactWrapper<P, S>;
函数签名错误,必须先声明泛型,例如:
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>;
如果您碰巧知道 P
和 S
是什么,您可以更具体一些,例如使用 <P extends React.Component, K>
。
如果我们想声明 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>;
}
}
}
详情
下面是上面每个构造的分解:
declare global
块:这个构造的目的是修改,如果你愿意的话,扩大全局范围,通过引入新声明或修改现有声明,从 within 非全局上下文,例如模块。我们的声明文件是一个模块,因为它包含一个从 Enzyme 导入ReactWrapper
的 top-levelimport
子句。 这样的块称为 "Global Augmentation",也可能出现在实现文件中。interface Global
包裹在namespace NodeJS
结构中:在我们的测试中,我们正在访问mountWithContext
函数作为全局变量的成员,顺便说一下global
,这是Node环境提供的。此变量已由 Node 的类型声明声明在与其他环境全局变量(例如process
)相同的级别。但是,我们需要通过添加新成员来扩充其 type。这个全局global
的类型是官方已经在namespace
NodeJS
中声明的interface
Global
节点的声明。我们通过声明interface
Global
的新成员来实现这一点。我们的扩充需要包含在包含Global
的namespace
中,否则它将被视为单独的interface
。粗略地说,词法范围适用。 (回想一下,TypeScript 接口可以在同一范围内多次声明,并且这些声明将被合并)
备注
我们把这个声明放在哪里? 任何会导致 TypeScript 获取它并将其包含在我们的编译上下文中的地方。 按照惯例,我们将把它放在项目根目录中名为 globals.d.ts 的文件中。 (从技术上讲,它可以命名为其他名称并进入较低的目录)。
请务必注意,此声明文件是我们应用程序代码的一部分,应检入源代码管理。 它必须 not 与第三方声明一起放在 typings、 等目录中node_modules/@types,或jspm_packages/npm/@types.
同样重要的是要注意,此增强仅影响 TypeScript 文件(.ts
、.tsx
、.d.ts
)。如果我们宁愿声明此函数由 TypeScript 语言服务获取,只是为了在 .js
或 .jsx,
文件中工作时提供智能感知,则此方法将不起作用。