如何将其他类型导入我的 TypeScript 自定义声明文件?
Posted
技术标签:
【中文标题】如何将其他类型导入我的 TypeScript 自定义声明文件?【英文标题】:How to import other types into my TypeScript custom declarations file? 【发布时间】:2017-06-13 07:02:28 【问题描述】:我的 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
函数,但类型是“错误的”。正确的定义应该是这样的:
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>;
【问题讨论】:
您是否试图让 TypeScript 获取声明以在.js
文件中使用或在 .ts
文件中使用?
@AluanHaddad 仅限 .ts
文件。
您可以添加您的tsconfig.json
文件吗?可能存在一些类型配置问题。另外,为了完整起见,您是否可以尝试在全局文件中声明像 cat() : ReactWrapper
这样的函数,以确认唯一的问题是声明而不是其他问题。
【参考方案1】:
函数签名错误,必须先声明泛型类型,例如:
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>
。
【讨论】:
这不可能...我仍然收到Cannot find name 'ReactWrapper'.
。
@tiagohngl 关于类型参数的声明是正确的。【参考方案2】:
如果我们想要声明 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
块:此构造的目的是通过引入新声明或修改现有声明,从 内部修改或增加全局范围 非全局上下文,例如模块。我们的声明文件是一个模块,因为它包含一个从 Enzyme 导入 ReactWrapper
的*** import
子句。
这样的块称为“全局增强”,也可能出现在实现文件中。
interface Global
包装在 namespace NodeJS
结构中:在我们的测试中,我们将 mountWithContext
函数作为全局变量的成员访问,顺便命名为 global
,它由 Node 环境提供.此变量已由 Node 的类型声明声明,与其他环境全局变量(例如 process
)处于同一级别。但是,我们需要通过添加一个新成员来扩充它的 type。这个全局 global
的 type 是 interface
Global
已经在 namespace
NodeJS
中声明,由 Node 的官方声明。我们通过声明interface
Global
的新成员来实现这一点。我们的扩充需要包裹在包含Global
的namespace
中,否则它将被视为单独的interface
。粗略地说,词法作用域适用。 (回想一下,TypeScript 接口可以在同一范围内多次声明,并且这些声明将被合并)
备注
我们在哪里放置这个声明? 任何会导致 TypeScript 将其拾取并将其包含在我们的编译上下文中的地方。 按照惯例,我们会将其放在项目根目录中名为 globals.d.ts 的文件中。 (从技术上讲,它可以命名为其他名称并放在较低的目录中)。
请务必注意,此声明文件是我们应用程序代码的一部分,应检查到源代码管理中。 它必须不与第三方声明一起放置在 typings、node_modules/@types 或 typings 等目录中strong>jspm_packages/npm/@types.
还需要注意的是,这种增强只影响 TypeScript 文件(.ts
、.tsx
、.d.ts
)。如果我们宁愿声明这个函数由 TypeScript 语言服务获取,只是为了在处理 .js
或 .jsx,
文件时提供智能感知,那么这种方法将行不通。
【讨论】:
不太好用。一旦我将import
语句添加到globals.d.ts
文件中,我的应用程序代码中的import KeyCodes from "constants/events/KeyCodes";
之类的内容就会停止与Cannot find module "constants/events/KeyCodes".
一起使用。
在第二次测试中...上面没有用,因为我使用的是typings/globals.d.ts
文件。如果我把它放在app/globals.d.ts
中,它就可以工作。但我不是很喜欢这个。我虽然 typings
文件夹用于声明,但现在我必须将声明与我的应用程序源代码混合。 :(
您对这个typings
文件夹用途的印象不正确。它适用于使用包管理器、类型或 tsd 安装的第三方声明,通常不会检查到源代码控制中。应用有自定义声明是很常见的,它们永远不应该放在那个文件夹中。
感谢您的澄清。如果您不介意,还有一个小问题,我们真的需要declare global namespace NodeJS interface Global
吗? global
、NodeJS
和 Global
是随机选择的还是有特殊含义?
没问题,我会在答案中添加其他信息。以上是关于如何将其他类型导入我的 TypeScript 自定义声明文件?的主要内容,如果未能解决你的问题,请参考以下文章
用于无类型 npm 模块的 TypeScript 自定义声明文件
typescript - tsc 如何将其他文件类型复制到 dist 文件夹
vue-class-component + typescript:如何在导入的函数中使用组件的类作为“this”的类型?