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

如何在TypeScript中编写其成员是给定类的子类的类型,typescript,Typescript,我想说的是,函数只返回扩展某个给定类的类 我试图定义一个类型AnimalClass interface AnimalClass { new( name : String ) : Animal ; } 我认为这意味着AnimalClass的实例是具有构造函数(或者我应该说“是构造函数”)的类,该构造函数接受字符串并构造Animal的实例 但是,下面的代码(我认为有错误)是用tsc版本1.7.5编译的 interface AnimalClass { new(

我想说的是,函数只返回扩展某个给定类的类

我试图定义一个类型
AnimalClass

    interface AnimalClass {
        new( name : String ) : Animal ;
    }
我认为这意味着AnimalClass的实例是具有构造函数(或者我应该说“是构造函数”)的类,该构造函数接受字符串并构造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
中,我需要
Lion
AnimalClass
的一个实例,但是
Lion
没有接受
字符串的构造函数

也许
Lion
Animal
继承了构造函数。这将解释为什么没有错误,为什么代码运行并打印“bob是一头狮子”

但是没有!如果我删除
Animal
中的构造函数,代码仍然可以编译。(尽管现在打印的是“未定义的是一头狮子”)

所以主要的问题是:

  • 如何编写一个类型来描述对象,这些对象是扩展给定类并提供具有给定参数列表的构造函数的类
次要问题:

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

  • 构造函数是在TypeScript中继承的吗


首先,将
字符串
类型更改为
字符串
string
表示原语类型,
string
表示
string
接口

构造函数是在TypeScript中继承的吗

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

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

class Lion extends Animal {
}

new Lion(); // error
如何编写一个类型来描述对象,这些对象是扩展给定类并提供具有给定参数列表的构造函数的类

你这样做很好。对于在新签名中指定的返回类型,它总是会出错,这对于大多数情况来说已经足够了。例如,向它传递一个结构与
Animal
不同的类将出错


正如您所发现的,在某些场景中它不会出错,您已经发现了其中的一个场景。当新签名的返回类型匹配时,似乎没有错误,但参数的数量不同。这就是为什么删除构造函数时不会出错。但是请注意,如果返回类型匹配,但至少有一个参数具有不同的类型,则会出错。

首先,将
字符串
类型更改为
字符串
string
表示原语类型,
string
表示
string
接口

构造函数是在TypeScript中继承的吗

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

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

class Lion extends Animal {
}

new Lion(); // error
如何编写一个类型来描述对象,这些对象是扩展给定类并提供具有给定参数列表的构造函数的类

你这样做很好。对于在新签名中指定的返回类型,它总是会出错,这对于大多数情况来说已经足够了。例如,向它传递一个结构与
Animal
不同的类将出错


正如您所发现的,在某些场景中它不会出错,您已经发现了其中的一个场景。当新签名的返回类型匹配时,似乎没有错误,但参数的数量不同。这就是为什么删除构造函数时不会出错。但是请注意,如果返回类型匹配,但至少有一个参数具有不同的类型,则会出错。

当您有包含参数的接口支持的方法时,将要求调用方传递参数,但不要求被调用方使用它

因此,如果接口需要传递一个参数,则忽略它是一个错误

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
所以在您的例子中,您已经定义了必须向动物的构造函数传递一个字符串。所有动物都必须传递一个字符串-这是您定义的通用签名。对于lions,字符串被忽略(因为它不需要)

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

function Lion() {
    _super.apply(this, arguments);
}
而且它使用了神奇的
参数
,这意味着名称实际上会一直延伸到基类。您可以通过序列化lion来测试这一点:

var lion = new Lion('Clarence');
alert(JSON.stringify(lion));
如果您在lion类中添加了构造函数,编译器会告诉您需要在构造函数中调用
super
,以及何时必须向其传递字符串:

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

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

因此,您的类型是准确的,但是TypeScript实用地应用了此信息,并且与JavaScript范例有关。

当您有包含参数的接口支持的方法时,调用方需要传递参数,但被调用方不需要使用参数

因此,如果接口需要传递一个参数,则忽略它是一个错误

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
所以在您的例子中,您已经定义了必须向动物的构造函数传递一个字符串。所有动物都必须传递一个字符串-这是您定义的通用签名。对于lions,字符串被忽略(因为它不需要)

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

function Lion() {
    _super.apply(this, arguments);
}
而且它使用了神奇的
参数
,这意味着名称实际上会一直延伸到基类。您可以通过序列化lion来测试这一点:

var lion = new Lion('Clarence');
alert(JSON.stringify(lion));
如果您在lion类中添加了构造函数,编译器会告诉您需要在构造函数中调用
super
,以及何时必须向其传递字符串:

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

    kind() : String { return "lion" ; }
}
你的类型是accurat