实现接口函数 - 声称不正确地实现接口

Posted

技术标签:

【中文标题】实现接口函数 - 声称不正确地实现接口【英文标题】:Implementing interface function - claims to incorrectly implement interface 【发布时间】:2017-12-13 01:53:59 【问题描述】:

目标

我最好尝试在项目中强制输入,以便任何实现 Animal 的人都必须提供此函数并确保该函数只能将 Woof 或 Meow 作为唯一参数,并且必须只返回其中一个呜呜声或喵喵声。

初步尝试

这是一些与我在 VSCode 中获得的代码(使用 TypeScript 2.4.1)类似(名称除外)的示例代码:

class Woof 
    constructor(private a: boolean = true) 


class Meow 
    constructor(private b: string = "abc")  


class Dog implements Animal  
    doSomething(sound: Woof): Woof 
        return new Woof();
    


class Cat implements Animal 
    doSomething(sound: Meow): Meow 
        return new Meow();
    


interface Animal 
    doSomething: <T extends Woof | Meow>(input: T) => T; 

如果我删除它 in the TypeScript playground,它会生成我期望的 javascript 而不会出错。

但是,在 VSCode 中,我在 Dog 和 Cat 类下都有一条红色波浪线,鼠标悬停会读取以下所有内容:

类“狗”错误地实现了接口“动物”。

属性“doSomething”的类型不兼容。

类型“(声音:Woof)=> Woof”不能分配给类型“(输入:T)=> T”。

参数“sound”和“sound”的类型不兼容。

类型“T”不能分配给类型“Woof”。

键入'Woof | Meow' 不能分配给类型 'Woof'。

类型 'Meow' 不能分配给类型 'Woof'。

类型“喵”中缺少属性“a”

每个错误都是嵌套的,因此很难在此处准确显示格式,但这似乎表明我在扩展泛型时不能只指定 Woof 或 Meow 类型,因为未实现私有属性两种类型(看起来类似于another question here)。尽管在文档中没有看到任何表明这是非法的东西(同样,在操场上,这似乎没有问题)。但是,与那个问题不同的是,我不希望泛型同时扩展这两种类型,而是仅限于其中一种。

阅读关于交集类型的帖子中的描述,它显示“联合类型 A | B 表示一个类型为 A 或类型 B 的实体,而交集类型 A & B 表示一个类型为 A 的实体和类型 B"。读到这里,我肯定想要一个联合类型,但这就是我上面所说的,而且似乎没有。

alternate 类下的波浪线中的类型被翻转,但消息是相同的。

当我在输出中使用“tsc”实际构建项目时,我也会收到此错误。

替代尝试 - 用每个实现的接口替换类型

我还尝试实现以下内容,希望它可以消除私有属性在 Woof 和 Meow 类之间匹配的奇怪需求(以防在指定每个类时出现意外情况并不起作用):

interface Sound 


class Woof implements Sound 
    constructor(private a: boolean = true) 


class Meow implements Sound 
    constructor(private b: string = "abc")  


class Dog implements Animal  
    doSomething(sound: Woof): Woof 
        return new Woof();
    


class Cat implements Animal 
    doSomething(sound: Meow): Meow 
        return new Meow();
    


interface Animal 
    doSomething: <T extends Sound>(input: T) => T; 

对于每个类,我都得到与以前完全相同的错误。

半工作版

现在,如果我完全消除泛型并仅使用上述替代方案中的接口,它可以解决部分目标,因为我可以将参数和结果限制为实现接口的类,但这并不完全理想因为它不会阻止其他开发人员传入一个接口实现并尝试返回另一个。

interface Sound 


class Woof implements Sound 
    constructor(private a: boolean = true) 


class Meow implements Sound 
    constructor(private b: string = "abc")  


class Dog implements Animal  
    doSomething(sound: Woof): Woof 
        return new Woof();
    


class Cat implements Animal 
    doSomething(sound: Meow): Meow 
        return new Meow();
    


interface Animal 
    doSomething: (input: Sound) => Sound; 

我更喜欢使用泛型并将 T 限制为一种实现的类型安全。关于如何使用泛型和 Typescript 在操场之外实际使用的语法来解决这个问题的任何想法?

【问题讨论】:

用重载代替泛型怎么样? @unional 我宁愿不这样做,因为我希望其他开发人员简单地被约束(通过类型系统)来实现 Animal 接口并被约束输入一种类型并输出相同的类型,每个特定选项都在 Animal 的函数定义本身中。虽然我可以合并类型,但我不能将这些约束合并到泛型本身上似乎很奇怪。 【参考方案1】:

这对你有用吗?

class Woof 
  constructor(private a: boolean = true)  


class Meow 
  constructor(private b: string = "abc")  


class Dog implements Animal<Woof> 
  doSomething(sound: Woof): Woof 
    return new Woof();
  


class Cat implements Animal<Meow> 
  doSomething(sound: Meow): Meow 
    return new Meow();
  


interface Animal<T extends Meow | Woof> 
  doSomething(input: T): T;

【讨论】:

效果很好 - 为什么这消除了将约束放在界面中而不是函数本身的错误? 因为函数依赖编译器来推断 T 的类型。在推断过程中,我认为它不能缩小类型。也许可以通过设计或进行一些改进。我给出的解决方案只是让它明确。

以上是关于实现接口函数 - 声称不正确地实现接口的主要内容,如果未能解决你的问题,请参考以下文章

当有多个实现接口的类时,如何指定构造函数注入[重复]

C# 显式接口成员实现

虚函数抽象函数以及接口的区别

为内部子接口创建“默认构造函数”

C#题 求大佬解答

如何将对象列表传递给函数,该函数需要实现接口的对象列表?