代码之家  ›  专栏  ›  技术社区  ›  Wayne Maurer

扩展typescript接口+优化函数签名

  •  2
  • Wayne Maurer  · 技术社区  · 6 年前

    是否可以定义一个对象接口,然后扩展接口,细化方法签名?

    我想和这个一起工作 strictFunctionTypes true .

    interface Plugin {
        addListener: (eventName: string) => void;
    }
    
    interface FooPlugin extends Plugin {
        addListener: (eventName: 'fooChanged') => void;
    }
    

    这里我得到以下错误:

    Interface 'FooPlugin' incorrectly extends interface 'Plugin'.
        Types of property 'addListener' are incompatible.
            Type '(eventName: "fooChanged") => void' is not assignable to type '(eventName: string) => void'.
                Types of parameters 'eventName' and 'eventName' are incompatible.
                    Type 'string' is not assignable to type '"fooChanged"'.
    

    下面是一个更复杂的例子,展示了我最终想要做的事情:

    export interface Plugin {
        addListener: (eventName: string, fn: Function) => void;
    }
    
    export interface FooPlugin extends Plugin {
        addListener: (eventName: 'fooInit', fn: (n: { i: boolean }) => void) => void;
        addListener: (eventName: 'fooDestroy', fn: (n: { d: number }) => void) => void;
    }
    
    2 回复  |  直到 6 年前
        1
  •  2
  •   Matt McCutchen    6 年前

    不管是好是坏,如果声明方法(不受 strictFunctionTypes )而不是函数值属性:

    interface Plugin {
        addListener(eventName: string): void;
    }
    
    interface FooPlugin extends Plugin {
        addListener(eventName: 'fooChanged'): void;
    }
    
        2
  •  3
  •   Francesco Pirrotta    6 年前

    我不太喜欢这个解决方案,但我想您需要这个来键入未键入的库,这样您就可以这样做:

    1) 在插件接口中添加泛型

    export interface Plugin<T, P> {
       addListener: (eventName: T, fn: (value: P) => void) => void;
    }
    

    2) 然后创建一个类型,使所有侦听器都正确键入

    export type FooPlugin = Plugin<'fooInit', { i: boolean }> & Plugin<'fooDestroy', { d: number 
    }>
    

    3) 最后在代码中使用它

    let plugin: FooPlugin = require("someLib");
    plugin.addListener('fooInit', ({i}) => ...); 
    plugin.addListener('fooDestroy', ({d}) => ...);