Typescript抽象方法重载

8 浏览
0 Comments

Typescript抽象方法重载

我想在抽象类中重载抽象方法,类似于这样:\n

abstract class Animal {
    public abstract communicate(sentence: string): void;
    public abstract communicate(notes: string[]): void;
}
class Human extends Animal {
    public communicate(sentence: string): void {
        // 做一些事情
    }
}
class Bird extends Animal {
    public communicate(notes: string[]): void {
        // 做一些事情
    }
}

\n然而,TypeScript报错,指出我错误地扩展了基类(Animal)。\n我是否做错了什么?是否预期某些根据面向对象编程应该正常工作的东西?还是TypeScript不支持这样的写法?\n注意:参数的类型可以是完全不同的类型,不像这个例子中那样。

0
0 Comments

TypeScript中的抽象方法重载问题是由于在派生类中调用基类的抽象方法时,基类的抽象方法没有正确地被重载导致的。

在给定的代码中,`BaseComponent`是一个抽象类,它定义了一个抽象方法`doSomethingMoreButOptional`,并在构造函数中接收一个`valueName`参数。派生类`DerivedComponent`继承自`BaseComponent`,并重写了`doSomethingMoreButOptional`方法。

在派生类的构造函数中,首先调用了基类的构造函数`super('derived')`,然后调用了基类的`doSomething`方法`super.doSomething()`。然而,由于`doSomething`方法中使用了未定义的变量`valueName`,导致代码无法编译通过。

解决这个问题的方法是,在`doSomething`方法中使用`this.valueName`代替`valueName`,以引用派生类中的`valueName`属性。修改后的代码如下所示:

export abstract class BaseComponent {
   constructor(protected valueName: string) {
   }
   protected doSomethingMoreButOptional(config: IConfig): void { }
   protected doSomething() {
       if (this.valueName === 'derived') {
           this.doSomethingMoreButOptional(new Config());
       }
   }
}
export class DerivedComponent extends BaseComponent {
   private _xxx: any[];
   private _yyy: any[];
   constructor() {
       super('derived');
       super.doSomething();
   }
   protected doSomethingMoreButOptional(config: IConfig): void {
       switch (config.ABC) {
          case 'xxx':
             config.options = this._xxx;
             break;
          case 'yyy':
             config.options = this._yyy;
             break;
          default:
             return;
       }
   }
}

通过使用`this.valueName`来引用派生类中的属性,代码可以正确地编译和执行,解决了抽象方法重载的问题。

0
0 Comments

Typescript中的抽象方法重载问题出现的原因是,抽象类期望子类实现两个方法签名。这两个方法签名分别是:

public abstract communicate(sentence: string): void;
public abstract communicate(notes: string[]): void;

可以通过以下方式来实现这两个方法签名:

class Human extends Animal {
    communicate(sentence: string); // optional overload signature
    communicate(notes: string[]);  // optional overload signature
    communicate(sentenceOrNotes: string | string[]) {
        // Do stuff
    }
}

最后一个方法签名是实现签名,它需要与需要实现的方法签名兼容。

关于子类的注意事项:

子类需要与基类兼容,这样当你这样做时...

const animal: Animal = new Bird();

...子类应该能够处理这两个调用:

animal.communicate("some sentence");
animal.communicate(["notes", "more notes"]);

在这种情况下,创建基于通信形式的单独接口(或使用混入)可能更合适:

interface CommunicatesWithSentences {
    communicate(sentence: string);
}
class Human extends Animal implements CommunicatesWithSentences {
    communicate(sentence: string) {
        // Do stuff
    }
}

但是,这种方法的问题是,在子类中两个方法仍然是有效的。当然,我可以在使用不期望的方法时抛出错误,但我认为这不是一个很好的解决方法,因为它仍然可以被调用。有没有办法实现这个要求呢?

0
0 Comments

Typescript抽象方法重载的原因是为了强制子类实现父类中的所有重载方法,而不仅仅是其中一个。然而,如果想要让Bird和Human拥有不同的communicate()参数类型并且由编译器强制执行,可以使用带有类型约束的泛型类型参数。

在上述代码中,Animal类是一个抽象类,它有一个泛型类型参数C,该参数的约束是string或string[]类型。Animal类中有一个抽象方法communicate(communication: C),子类必须实现这个方法。

Human类继承Animal类,并指定泛型类型参数为string。它实现了communicate(sentence: string)方法。

Bird类也继承Animal类,并指定泛型类型参数为string[]。它实现了communicate(notes: string[])方法。

Bynar类继承Animal类,并指定泛型类型参数为boolean。由于boolean类型不满足约束string或string[],所以编译器会报错。

通过使用泛型类型参数,我们可以在编译时强制要求Bird和Human拥有不同的communicate()参数类型。

最后的代码示例展示了如何使用这些类。对于Human对象,我们可以传入一个字符串作为参数,但不能传入一个字符串数组;对于Bird对象,我们可以传入一个字符串数组作为参数,但不能传入一个字符串。

此外,值得一提的是,我们还可以利用TypeScript 2.3中的默认类型参数来简化代码。

至于参数个数不同的情况(例如1个和3个),在这种情况下,抽象方法重载是不适用的,因为抽象方法重载要求子类实现所有重载方法。如果参数个数不同,可以考虑使用可选参数或重载函数来实现不同个数的参数。

0