javascript 在TypeScript中接受一组接口时,是否有一种不那么冗长的方法?

xzv2uavs  于 2022-12-10  发布在  Java
关注(0)|答案(1)|浏览(130)

问题

这是我的问题的一个大大简化的变体:
我有一个模型,看起来像这样:

interface Instrument {
    // ...properties that all instruments have in common...
}

interface Guitar extends Instrument {
    // ...properties that only a guitar has...
}

interface Flute extends Instrument {
    // ...properties that only a flute has...
}

interface Artist {
    instrument: Guitar | Flue
}

现在,每当我添加一个新乐器时,我必须记住将它添加到艺术家接受的乐器中。我想知道是否有一种方法可以定义某种抽象的乐器接口,并告诉Artist.instrument接受扩展Instrument的每个接口。

期望

因此,理想情况下,它应该类似于:

interface Artist {
    instrument: // everything that inherits from or extends Instrument
}

我也愿意考虑其他的方法,如果有更简单的方法可以解决这个问题,请告诉我。
我所尝试的
我已经尝试过简单地接受Instrument作为Artist.instrument的类型,但是没有成功。

interface Artist {
    instrument: Instrument
}

在这种情况下,我得到了每个属性的错误,这些属性不是由所有仪器共享的。

n6lpvg4x

n6lpvg4x1#

我猜你所做的尝试产生了如下错误:

interface Instrument {
    key: string;
}

interface Guitar extends Instrument {
    isElectric?: boolean;
    stringCount: number;
}

interface Flute extends Instrument {
    bodyType: "wood" | "metal";
}

interface Artist {
    instrument: Instrument
}

const artist:Artist = {
    instrument: {
        key: "A",
        stringCount: 12,
    },
};

其中stringCount属性产生此错误:

Type '{ key: string; stringCount: number; }' is not assignable to type 'Instrument'.
  Object literal may only specify known properties, and 'stringCount' does not exist in type 'Instrument'.

这里的问题是,您可以从字面上定义从Instrument继承的接口定义的任何可能的属性,而TypeScript无法验证它不知道的属性。
一种解决方案是将乐器定义分解为TypeScript可以验证的单独变量:

const instrument:Guitar = {
    key: "A",
    stringCount: 12,
};
const artist:Artist = {
    instrument,
};

这不会产生错误。TypeScript很满意,因为instrument变数可以验证,而且可以指派给artistinstrument属性,因为它满足界面。
另一个解决方案是使Artist成为泛型类型,您可以在其中更显式地定义艺术家演奏的乐器类型(为方便起见,默认为Instrument):

interface Artist<T extends Instrument=Instrument> {
    instrument: T
}

const artist:Artist<Guitar> = {
    instrument: {
        key: "A",
        stringCount: 12,
    }
};

相关问题