Typescript类扩展Partial接口

10

我想创建一个类,具有接口的所有属性,但实际上并未声明这些属性。接口属性在构建过程中添加,且将在运行时存在。

我找到了这篇文章,指导我使用Partial<T>……但似乎不起作用。以下代码没有产生编译错误。

interface Animal {
    name: string;
}

interface HasConstructor {
    constructor: any;
}
//Do this to supress this error: "Type 'Dog' has no properties in common with type 'Partial<Animal>"
type OptionalAnimal = Partial<Animal> & HasConstructor;

class Dog implements OptionalAnimal {
    public constructor() {

    }
    public breed: string;
}

然而,在 Dog 的实例上并不可用 name 属性。
var spot = new Dog();
spot.name = "Spot"; //ERROR: Property 'name' does not exist on type 'Dog'

我可以通过创建另一种类型并像这样引用来解决这个问题:

type AnimalDog = Dog & Animal;

var spot: Animal = new Dog() as any;
spot.name = "Spot";


然而,我无法构建一个新的AnimalDog实例,并且必须将其强制转换为any以使类型匹配,因此根据场景,我的代码中使用了AnimalDogDog两种类型。这还会在引用Animal类型时在Dog内部产生编译错误。
有没有一种方法可以告诉TypeScript该类实现了接口,而不需要显式声明每个接口属性?

constructor: any 这个属性的意义是什么?所有对象已经拥有了这个属性。 - Titian Cernicova-Dragomir
有没有一种方法可以告诉 TypeScript 类实现了接口,而不必显式声明每个接口属性?不行。这就是类的作用,而不是接口。接口在运行时不存在。请创建一个类,而不是一个接口,并扩展它而不是实现它。 - Roberto Zvjerković
为什么Dog要成为一个类呢?如果你在构建过程中创建了所有内容,那就让它成为接口吧。 - smnbbrv
@smnbbrv 我在构建过程中并不会创建 everything,只是从接口中添加缺失的部分。我的示例与我们的实际情况并不完全相同,但 Dog 有它自己的属性,我们实际上需要运行 new Dog(),需要一个具体的类实例。 - TwitchBronBron
1个回答

14
问题在于Partial<T>只允许您实现成员,但不会要求您这样做,如果您不实现成员,则它将不会出现在类中。
您可以创建一个返回类的函数,该类将实现接口。返回的类实际上不需要声明任何字段,因此它们都将是undefined,但这应该没关系,因为字段必须是可选的。
interface Animal {
    name: string;
}

type OptionalAnimal = Partial<Animal>;
function autoImplement<T>(): new () => T {
    return class { } as any;
}
class Dog extends autoImplement<OptionalAnimal>() {
    public constructor() {
        super();
    }
    public breed: string;
}

var spot = new Dog();

spot.name = "Spot"; // ok now

您也可以将 Dog 类型转换为指定返回实例具有 Animal 的成员,但这些新成员将无法从类内部访问:

interface Animal {
    name: string;
}

class _Dog {
    public constructor() {

    }
    public breed: string;
}

const Dog = _Dog as { new(): _Dog & Partial<Animal> } & typeof _Dog
type Dog = InstanceType<typeof Dog>

var spot = new Dog();

spot.name = "Spot"; 

你的 autoImplment 解决方案完全符合我的需求!谢谢! - TwitchBronBron
我建议定义autoImplement()函数,以便它只允许T成为弱类型,至少在打开--strictNullChecks时。 - jcalz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接