【问题标题】:How to deal with type name conflicts in a typescript definition file如何处理打字稿定义文件中的类型名称冲突
【发布时间】:2018-12-22 01:16:34
【问题描述】:

我正在尝试为已经存在的库编写打字稿定义文件。这个库 (react-filepond) 导出了一个名为 File 的对象(可以在 usage example in the README 中看到)。

问题在于这个库创建的另一个接口使用了JS File interface

所以现在在我的打字稿定义文件中,我必须以某种方式管理File 类型的两个定义。我对此的解决方案是在我的定义文件中将库创建的对象声明为不同的名称,然后简单地将其导出为“文件”。

declare class FilePondFile extends React.Component<FilePondFileProps> { }
export { FilePondFile as File };

当我在自己的项目中使用该类型时,这看起来很好而且很漂亮。但作为 OSS 的支持者,我想通过Definitely Typed repo 将这个定义提供给社区。​​p>

他们的 linter 给了我一个错误,尽管这显然阻止了 my PR 被审查:

Error: C:/dev/DefinitelyTyped/types/react-filepond/index.d.ts:22:1
ERROR: 22:1   strict-export-declare-modifiers  'declare' keyword is redundant here. 
See: https://github.com/Microsoft/dtslint/blob/master/docs/strict-export-declare-modifiers.md

乍一看,删除class FilePondFile前面的declare似乎很简单,但是,如果我删除它,我会得到一个不同的错误:

A 'declare' modifier is required for a top level declaration in a .d.ts file. 

所以我不确定如何处理这种矛盾。绝对类型的维护者似乎没有时间提供帮助,因为我的 PR 刚刚被标记为“需要作者注意”,尽管我明确提出了这个问题。

有没有人建议我可以做些什么来避免在此定义文件中重复对 File 的引用,同时还传递绝对类型化 linter?

【问题讨论】:

  • 当前的 dtslint 规则似乎不可能实现您想要实现的目标,您可以尝试在 dtslint repo 中提出问题
  • 好主意,谢谢!我已经这样做了here

标签: typescript definitelytyped


【解决方案1】:

问题在于另一个接口 库创建利用 JS 文件接口。

还有另一种解决方案。

File 名称由从该模块声明和导出的类使用。

您必须在同一个模块中描述FilePondItem 接口,并且它必须具有file 类型不同的file 属性-它必须引用在lib.dom 中定义的全局File 对象.d.ts

export interface FilePondItem {
    file: File;

TypeScript 类型是结构化的。你不必通过名字来引用全局的File类型,你可以提供它的定义,兼容lib.dom.d.ts中的那个:

export interface FilePondItem {
    file: Blob & {readonly lastModified: number; readonly name: string};

只要类型定义保持兼容,一切都会好起来的。

当然也有缺点:它是一个重复的代码,它更冗长,并且如果全局 File 类型发生变化,它有可能在未来与实际的 File 不兼容(但我认为这不太可能)。

【讨论】:

  • 这是个好主意,谢谢!不幸的是,在采用了 Karol 的original answer 之后,linting 错误消失了,我的拉取请求在你发布这个答案前几分钟就被合并了。我会在不久的将来进行修改。
【解决方案2】:

这个错误信息:

一个'declare'修饰符在一个顶级声明中是必需的 .d.ts 文件。

在声明文件不导出任何内容时显示。 declare 关键字是多余的,因为它已经在 *.d.ts 文件中被假定了。

拥有声明文件的目的是准确描述相应 JavaScript 模块中发生的事情。 At the time of writing this postreact-filepond 包含 3 个命名导出:const registerPluginclass FilePondclass File。这意味着您的声明可能如下所示:

types/react-filepond/index.d.ts

import * as React from 'react';
import { registerPlugin } from 'filepond';

export { registerPlugin };

interface Props { /* FilePond props here */ }

export class FilePond extends React.Component<Props> { }

export class File extends React.Component { }

因为这就是模块中真正发生的事情。注意:如果没有 filepond 的类型,最好先为该库创建类型。

如果消费者遇到命名冲突,他们的职责是在本地提供别名:

import { File as FileComponent } from 'react-filepond';

由于每个人都可以有不同的设置,因此您(作为打字作者)无法避免发生冲突。库作者最好避免使用这样的名称,但如果他们不这样做,类型定义应该尊重他们的选择。

【讨论】:

  • 但这是一种误导,因为这个 javascript 库不会导出任何名为 FilePondFile 的内容 - 任何尝试使用该名称的人都会在运行时得到 ReferenceError: Cannot find variable: FilePondFile
  • 你是对的,这是一个俯瞰。我更新了答案。
  • KarolMajewski 我准备将您的原始答案标记为正确,但我相信您更新的答案不再解决避免名称冲突的问题。 @artem 有一个非常有效的观点,即同时导出两者会产生误导,但目前我认为有一个稍微误导性的类型定义比根本没有一个更好。如果你恢复你原来的答案,我会重新标记它!
  • 谢谢,但这不公平——声明文件的目的是准确描述相应 JavaScript 模块中发生的事情。在这种情况下,模块有 3 个命名导出:const registerPluginclass FilePondclass File。由于它们被命名为导出,因此您需要保留它们的名称,否则,库使用者可能会遇到问题。如果发生冲突,消费者的职责是提供别名以防止冲突 (import { File as FileComponent } from 'react-filepond';)。
猜你喜欢
  • 2013-03-26
  • 2020-06-08
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
  • 2019-02-27
  • 2015-02-16
  • 2022-01-02
  • 2021-05-26
相关资源
最近更新 更多