如何在TypeScript中编写其成员是给定类的子类的类型

时间:2016-01-14 21:35:03

标签: typescript

我希望能够说一个函数只返回扩展某个给定类的类。

我尝试的是定义类型AnimalClass

    interface AnimalClass {
        new( name : String ) : Animal ;
    }

我认为这意味着AnimalClass的实例是具有构造函数的类(或者我应该说"是构造函数"),它接受String并构造Animal的实例。

但是下面的代码,我认为有错误,用tsc版本1.7.5编译。

interface AnimalClass {
    new( name : String ) : Animal ;
}

abstract class Animal {
    name : String ;
    constructor( name : String ) { this.name = name } 
    abstract kind() : String ;
}

class Lion extends Animal {
    kind() : String { return "lion" ; }
}

function getAnimalClass() : AnimalClass {
    return Lion ;  //  Shouldn't this be an error?
}

function makeAnimal() : Animal {
    const klass = getAnimalClass() ;
    return new klass( "bob" ) ;
}

var a = makeAnimal() ;
console.log( a.name + " is a " + a.kind() ) ;

我认为这是错误的,因为在函数getAnimalClass中我需要LionAnimalClass的实例,但是Lion没有带{的String的构造函数{1}}。

或许LionAnimal继承构造函数。这可以解释为什么没有错误以及为什么代码运行和打印" bob是狮子"

但不!如果我删除Animal中的构造函数,代码仍会编译。 (虽然现在它打印" undefined是狮子")。

所以主要的问题是:

  • 如何编写描述对象的类型,这些对象是扩展给定类的类,并为构造函数提供给定的参数列表?

次要问题:

  • 为什么上面的代码没有错误?

  • 是否在TypeScript中继承了构造函数?

2 个答案:

答案 0 :(得分:3)

当你有一个由包含参数的接口支持的方法时,调用者将被要求传递一个参数,但是被调用者不需要使用它。

因此,如果接口需要传递参数,则省略它是错误的。

interface Example {
    (x: number): void;
}

var giveMeANumber: Example = function (num: number) {

}

giveMeANumber(); // Error

但忽略已传递的参数并不是错误。

interface Example {
    (x: number): void;
}

var giveMeANumber: Example = function () {

}

giveMeANumber(15); // No Error

所以在你的情况下,你已经定义了必须将一个字符串传递给它们的构造函数。所有动物都必须传递一个字符串 - 这是您定义的常用签名。在狮子会的情况下,字符串被忽略(因为它不需要)。

在您的示例中,如果查看生成的代码,您将看到当您在子类中省略构造函数时,会为您生成一个:

function Lion() {
    _super.apply(this, arguments);
}

它使用了神奇的arguments,这意味着名称实际上已经到了基类。你可以通过序列化狮子来测试这个:

var lion = new Lion('Clarence');
alert(JSON.stringify(lion));

如果你在狮子类中添加了一个构造函数,编译器会告诉你需要在构造函数中调用super,然后你必须将一个字符串传递给它:

class Lion extends Animal {
    constructor() {
        super('HARD-CODED');
    }

    kind() : String { return "lion" ; }
}

因此,您的类型是准确的,但TypeScript实际应用此信息,并尊重JavaScript范例。

答案 1 :(得分:1)

首先,将String类型更改为stringstring用于基本类型,String表示String接口。

  

构造函数是否在TypeScript中继承?

是。您可以进行快速测试以查看:

abstract class Animal {
    constructor(name: string) {}
}

class Lion extends Animal {
}

new Lion(); // error
  

如何编写描述对象的类型,这些对象是扩展给定类的类,并为构造函数提供给定的参数列表?

你这样做的方式很好。对于新签名中指定的返回类型,它始终是错误的,这对于大多数情况都是足够的。例如,传递一个具有与Animal不同结构的类将会出错。

正如您已经发现的那样,在某些情况下它并没有发生错误,而且您已经发现其中一种情况。当新签名的返回类型匹配时似乎没有错误,但参数的数量不同。这就是为什么在删除构造函数时它不会出错的原因。但请注意,如果返回类型匹配,则会出错,但至少有一个参数的类型不同。