TypeScript:覆盖和修复包的类型定义

Posted

技术标签:

【中文标题】TypeScript:覆盖和修复包的类型定义【英文标题】:TypeScript: override and fix typing definitions for packages 【发布时间】:2018-07-24 02:45:38 【问题描述】:

我正在使用 React victory 库来制作图表,并且我正在使用 TypeScript。我已将 @types/victory 包添加到我的项目中,但不幸的是,它缺少一堆我需要的 key 定义。对于某些接口,它缺少几个属性,因此(使用this answer),我创建了一个自定义文件来将这些属性添加到接口。

但是,现在我有一个问题:为事件定义的接口定义了一个名为eventHandlers 的属性,但它又缺少一个重要的定义,它是如何定义的:

export interface EventPropTypeInterface<TTarget, TEventKey> 
  /* other properties */,
  eventHandlers: 
    [key: string]:
       (event: React.SyntheticEvent<any>): EventCallbackInterface<TTarget, TEventKey>  |
       (event: React.SyntheticEvent<any>): EventCallbackInterface<TTarget, TEventKey>[] 
  

但是,问题是函数应该允许接受第二个参数,例如(我不确定第二个参数的类型,所以我有any):

 (event: React.SyntheticEvent<any>, dataPoint: any): EventCallbackInterface<TTarget, TEventKey> 

所以,我尝试将这个属性包含在我自己的定义中:

declare module "victory" 
  export interface EventPropTypeInterface<TTarget, TEventKey> 
  eventHandlers: 
    [key: string]:
       (event: React.SyntheticEvent<any>, dataPoint: any): EventCallbackInterface<TTarget, TEventKey>  |
       (event: React.SyntheticEvent<any>, dataPoint: any): EventCallbackInterface<TTarget, TEventKey>[] 
  

但是现在,TypeScript 在抱怨@typings 目录下的index.d.ts,说eventHandlers 必须是我定义的类型。

有没有办法使用提供的类型定义文件,并以某种方式用我自己的定义“增强”它,类似于我在添加新属性时对其他接口所做的那样?

【问题讨论】:

几天前我问了一个类似的问题,答案的要点是“无法重新定义定义文件中的属性”:***.com/a/48692419/1063392。但如果这是不正确的,我会很高兴! 它是否只是 allow 另一个参数而不是 require 一个?如果是这样,也许将其更改为可选,例如 dataPoint?: any 而不是 dataPoint: any @jcalz 我也有同样的想法,不幸的是,它似乎根本不起作用。 【参考方案1】:

这可以工作。问题是类型的定义没有考虑到可扩展性。

对象字面量类型,例如x: string,在许多情况下都很棒,但不适用于复杂的嵌套结构。

原因是这些类型,类似于类型别名,受制于启用可扩展性所需的声明合并。

如果eventHandlers 对象的可能值的类型被声明为interface,则只需添加额外的重载即可轻松扩展它。

以下自包含示例显示了当类型被重构为使用interface 声明eventHandlers 的值类型时,可扩展性是多么容易:

declare module "victory" 
    interface EventHandler<TTarget, TEventKey> 
        (event: React.SyntheticEvent<any>): EventCallbackInterface<TTarget, TEventKey>
        (event: React.SyntheticEvent<any>): EventCallbackInterface<TTarget, TEventKey>[]
    

    export interface EventPropTypeInterface<TTarget, TEventKey> 
        eventHandlers: 
            [key: string]: EventHandler<TTarget, TEventKey>

        
    

declare module "victory" 
    // this interface merges with the original, declaring additional overloads of the all signature
    interface EventHandler<TTarget, TEventKey> 
        // declare overloads
        (event: React.SyntheticEvent<any>, dataPoint: any): EventCallbackInterface<TTarget, TEventKey>
        (event: React.SyntheticEvent<any>, dataPoint: any): EventCallbackInterface<TTarget, TEventKey>[]
    


type EventCallbackInterface<T, U> = 
declare namespace React 
    export type SyntheticEvent<T> = ;

测试:

import victory = require("victory");

declare const handlerProps: victory.EventHandler<, >;

handlerProps(,  x: 1, y: 2 ); // works fine

Here is a link to it in action

我强烈建议您向https://github.com/DefinitelyTyped/DefinitelyTyped 提交一个拉取请求,该请求将npm:@types/victory 修改为以这种方式使用interface 以启用这种可扩展性。

【讨论】:

感谢您的详细解答。尽管我希望找到解决问题的方法,但根据您的解释,这是不可能的。一个问题:你为什么在你的代码中声明EventHandlerMap?我不确定我是否理解它为什么会出现 @Farzad nice catch 是实验的产物。删除它 感谢您的澄清!只有一件事:如果我有时间提交拉取请求,我可以使用你的代码吗? 当然欢迎你。如果你觉得有帮助,你也可以在 PR 中链接这个答案

以上是关于TypeScript:覆盖和修复包的类型定义的主要内容,如果未能解决你的问题,请参考以下文章

如何在 TypeScript 中指定定义为对象文字的箭头函数的类型?

如何覆盖 TypeScript UMD 全局类型定义?

typescript 关于class属性类型定义被属性默认值覆盖的问题及解决方式

php代码审计整理

如何在等待中指定 Typescript Mongoose 模型类型

Typescript 解析私有范围包的类型