如何将其他类型导入我的 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>;

如果您碰巧知道PS 是关于什么的,那么您可以更具体一些,例如使用&lt;P extends React.Component, K&gt;

【讨论】:

这不可能...我仍然收到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。这个全局 globaltypeinterface Global 已经在 namespace NodeJS 中声明,由 Node 的官方声明。我们通过声明interfaceGlobal 的新成员来实现这一点。我们的扩充需要包裹在包含Globalnamespace 中,否则它将被视为单独的interface。粗略地说,词法作用域适用。 (回想一下,TypeScript 接口可以在同一范围内多次声明,并且这些声明将被合并)

备注

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

请务必注意,此声明文件是我们应用程序代码的一部分,应检查到源代码管理中。 它必须与第三方声明一起放置在 typingsnode_modules/@typestypings 等目录中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 吗? globalNodeJSGlobal 是随机选择的还是有特殊含义? 没问题,我会在答案中添加其他信息。

以上是关于如何将其他类型导入我的 TypeScript 自定义声明文件?的主要内容,如果未能解决你的问题,请参考以下文章

用于无类型 npm 模块的 TypeScript 自定义声明文件

如何导入其他 TypeScript 文件?

typescript - tsc 如何将其他文件类型复制到 dist 文件夹

vue-class-component + typescript:如何在导入的函数中使用组件的类作为“this”的类型?

如何将 plotly.js 导入 TypeScript?

如何将 typescript npm 模块导入语法转换为 ECMA2015 模块导入语法