仅声明带有名称的方法签名的类的接口

时间:2018-12-25 16:58:22

标签: javascript node.js typescript

假设我有一个包含许多方法的类,但我肯定知道它们的签名匹配。

是否可以在不描述此类的特定方法的情况下描述此类的接口?就像这里:

interface IController {
  (input: string): number // any method without reference to its name
}

class Controller implements IController {
  method1(input: string): number { ...do something }
  method2(input: string): number { ...do something }
  ...
}

还是不可能?

3 个答案:

答案 0 :(得分:3)

具有索引签名的选项(如他的答案中的@ fk82概述)具有不希望出现的结果,它迫使您向该类添加索引签名。这意味着您的类将可以由任意字符串索引,而这可能不是您想要的。

如果您的目标只是强制实现者类仅具有具有给定签名的方法,则更好的选择是使用映射类型:

type IController<K extends PropertyKey> = { 
    [P in K]: (input: string) => number;
}

class Controller implements IController<keyof Controller> {
    method1(input: string): number { return input.length; }
    method2(input: string): number { return input === '' ? 0 : 1; }
}

let a = new Controller();
a['aa'] // not allowwed under no implicit any 

这具有一个额外的优点,即允许该类具有一些不符合签名要求的方法,但需要以显式方式进行:

class Controller implements IController<Exclude<keyof Controller, 'special'>> {
    method1(input: string): number { return input.length; }
    method2(input: string): number { return input === '' ? 0 : 1; }
    special() { }
}

答案 1 :(得分:2)

您可以使用attrs

interface IController {
  [name: string]: (input: string) => number;
}

一个小警告是TypeScript编译器现在将要求您将索引签名添加到实现IController的每个类中。即您需要按以下方式定义Controller类:

class Controller implements IController {
    [name: string]: (input: string) => number;
    method1(input: string): number { return input.length; }
    method2(input: string): number { return input === '' ? 0 : 1; }
}

这是一个index signature,上面有完整的示例。请注意,索引签名将在断言中进行测试,例如

const A = {
    m(input: string): number { return input.length; },
} as IController;

const B = {
    m(input: string): string { return input; }
} as IController;

,由于返回值B,分配string将引发类型错误。

答案 2 :(得分:0)

根据@ FK82的回答,您可以修改某些内容以适合您所寻求的解决方案,但这将违反Interface构造的目的,该构造将对象绑定到一堆编译时已知的签名。引用接口时,编译器将如何知道您具体指的是什么方法?

但是,据我所知,为什么不尝试编写基于接口的解决方案,而不是在执行代码中声明功能抽象呢?只需描述一下函数签名,然后转换为合适的方法即可,因为在JS / TS中,函数是一等公民。

type Strategy = (input: string) => number;

class Controller implements IController {
    method1(input: string): number { ...do something }
    method2(input: string): number { ...do something }
}

function useMethod(f: Strategy): any {
  ...
  const i = f('my string');
  ...
}

function main() {
    const c = new Controller ();
    const method = chooseOne === true ? c.method1 : c.method2;
    useMethod (method);
}

这种处理方式与OOP中的Strategy Pattern不太相似,但是FP解决方案更精简,在我看来,它是Javascript / Typescript的更好功能之一。