Typescript 别名泛型接口

Posted

技术标签:

【中文标题】Typescript 别名泛型接口【英文标题】:Typescript alias generic interface 【发布时间】:2021-09-16 00:53:16 【问题描述】:

我正在尝试将以下代码用于事件调度程序,并更加指定使用的类型(类和接口)。

请注意,我通常有兴趣了解为什么我在此处使用类型/类/接口/泛型类型不起作用,并且对事件本身不太感兴趣。

Original code:

type Handler<E> = (event: E) => void;

class EventDispatcher<E>  
    private handlers: Handler<E>[] = [];
    fire(event: E)  
        for (let h of this.handlers)
            h(event);
    
    register(handler: Handler<E>)  
        this.handlers.push(handler);
    
 

我想要达到的目标:

使用 Typescript 的 CustomEvent&lt;any&gt; 而不是 E

能够定义extendsCustomEvent&lt;any&gt;的具体自定义事件,例如:

export class FormClearedEvent extends CustomEvent<any> 
   constructor() 
     super("formCleared");
   

导出那些特定的自定义事件,连同处理程序和事件分派器

第一次尝试,未编译:

export type Handler<CustomEvent<any>> = (event: CustomEvent<any>) => void;    // <-- doesn't compile
// Also, using CustomEvent<any> as the type parameter for the dispacther and its methods, doesn't compile as well. 

第二次尝试,让我到处重复SpecificEvent extends CustomEvent&lt;any&gt;&gt;并且无法编译:

export type Handler<SpecificEvent extends CustomEvent<any>> = (event: SpecificEvent) => void;
export class EventDispatcher<SpecificEvent extends CustomEvent<any>> 
    private handlers: Handler<SpecificEvent extends CustomEvent<any>>[] = []; // <-- doesn't compile
    fire(event: SpecificEvent extends CustomEvent<any>)                      // <-- doesn't compile
        for (let handler of this.handlers) 
            handler(event);
        
    
    register(handler: Handler<SpecificEvent extends CustomEvent<any>>)       // <-- doesn't compile
        this.handlers.push(handler);
    


// specific events
export class FormClearedEvent extends CustomEvent<any> 
   constructor() 
     super("formCleared");
   

第三次尝试,成功了,但现在我有两个真正相同的课程(CustomEvent&lt;any&gt;SpecificEvent):

// specific events
class SpecificEvent extends CustomEvent<any>  
export class FormClearedEvent extends CustomEvent<any> 
   constructor() 
     super("formCleared");
   


// SpecificEvent handler
export type Handler<SpecificEvent> = (event: SpecificEvent) => void;

// SpecificEvent dispatcher
export class EventDispatcher<SpecificEvent> 
    private handlers: Handler<SpecificEvent>[] = [];
    fire(event: SpecificEvent) 
        for (let handler of this.handlers) 
            handler(event);
        
    
    register(handler: Handler<SpecificEvent>) 
        this.handlers.push(handler);
    

我的问题:

    为什么我的第一次尝试没有编译? 为什么我第二次尝试的某些代码无法编译? 我能比第三种方法做得更好吗?

【问题讨论】:

【参考方案1】:

与直觉相反,如果我们使用意义不大的名称,这可能更有意义。

在第一种情况下,打字稿正在寻找这样的东西:

export type Handler<T> = (event: T) => void;

我们正在尝试使用CustomEvent&lt;any&gt; 作为类型参数:

export type Handler<CustomEvent<any>> = (event: CustomEvent<any>) => void; 

-- 这不是一个有效的名称。这就解释了为什么我们的第二次尝试超过了这一点;我们给它一个有效的名字SpecificEvent,并限制它扩展CustomEvent

export type Handler<SpecificEvent extends CustomEvent<any>> = (event: SpecificEvent) => void;

同样,现在我们的类声明中有一个名为 SpecificEvent 的泛型类型:

export class EventDispatcher<SpecificEvent extends CustomEvent<any>> 

-- typescript 认为后面的extends 将是条件类型,并期望一个问号。

看起来您可以按照以下方式做一些事情:

export type Handler<E extends CustomEvent> = (event: E) => void;

export class EventDispatcher<E extends CustomEvent> 
  private handlers: Handler<E>[] = [];
  fire(event: E) 
    for (let handler of this.handlers) 
      handler(event);
    
  
  register(handler: Handler<E>) 
    this.handlers.push(handler);
  

【讨论】:

(1) 但是为什么CustomEvent&lt;any&gt; 不能代替T?我以为T 意味着什么,但事实并非如此;具体来说,它并不意味着泛型类型,对吧?你能链接到一些指定的文档吗? (2) 为什么Typescript认为它是class EventDispatcher定义内的条件类型,而不是Handler定义内的条件类型?

以上是关于Typescript 别名泛型接口的主要内容,如果未能解决你的问题,请参考以下文章

前端进阶-TypeScript高级类型 | 泛型约束泛型接口泛型工具类型

来自接口实现的 Typescript 泛型推断

TypeScript泛型

TypeScript泛型

现代编程语言:TypeScript

从 JavaScript 到 TypeScript - 接口