[英]Intersection types with interfaces fails to throw TypeScript error
By mixing TypeScript types with interfaces in an intersection, I seem to loose the stricter behaviour of interfaces in my code.通过在交叉点中将 TypeScript 类型与接口混合,我似乎放松了代码中接口的更严格行为。 I want to be able to compose types using intersections (such that I can narrow down a type in specific instances), but I want to be able to keep the exactness of interfaces.我希望能够使用交集来组合类型(这样我可以在特定情况下缩小类型),但我希望能够保持接口的准确性。
Take this code:拿这个代码:
type Vehicle = {
name: string
properties: Record<string, unknown>
}
interface CarProperties {
electric?: boolean
}
type Car = Vehicle & {
name: 'car'
properties: CarProperties
}
const car: Car = {
name: 'car',
properties: {
electric: false,
someOther: 'bs' // <= I want this to throw a TS Error
}
}
As the CarProperties
is an interface, I would expect it to disallow the inclusion of the someOther
key.由于CarProperties
是一个接口,我希望它不允许包含someOther
键。
Why is this not the case?为什么不是这样? And how else would one go about achieving the same thing?还有一个 go 如何实现同样的目标?
The problem is the intersection type Car
.问题是路口类型Car
。 This leads to properties
of car being a Record<string, unknown> & CarProperties
and thus allows string keys.这导致 car 的properties
是Record<string, unknown> & CarProperties
,因此允许字符串键。
To achieve what you want, you can add a generic to your Vehicle type:为了实现您想要的,您可以将泛型添加到您的车辆类型:
type Vehicle<T extends object> = {
name: string
properties: T
}
type GenericVehicle = Vehicle<Record<string, unknown>>;
interface CarProperties {
electric?: boolean
}
interface Car extends Vehicle<CarProperties> {
name: 'car'
}
PS: I noticed you call this a "union type", which it is not . PS:我注意到您将其称为“联合类型”, 但事实并非如此。 Intersection types share the properties of the intersected types, whereas union types can be either of the unionized types.交叉类型共享交叉类型的属性,而联合类型可以是联合类型中的任何一种。
You can make electric
property a required one and use object
type instead of Record<string, unknown>
.您可以将electric
属性设为必需属性,并使用object
类型而不是Record<string, unknown>
。
type Vehicle = {
name: string
properties: object, // <---- change
}
type CarProperties = {
electric: boolean // is required now
}
type Car = Vehicle & {
name: 'car'
properties: CarProperties
}
// ok
const car2: Car = {
name: 'car',
properties: {
electric: false,
}
}
// expected error
const car4: Car = {
name: 'car',
properties: []
}
// expected error
const car5: Car = {
name: 'car',
}
// error
const car3: Car = {
name: 'car',
properties: {}
}
// error
const car: Car = {
name: 'car',
properties: {
electric: false,
someOther: 'bs' // error
}
}
I know, using object
type is controversial a bit, because of this rule, but you can find more information about pros and cons in this answer.我知道,由于这条规则,使用object
类型有点争议,但你可以在这个答案中找到更多关于利弊的信息。
If you have more variants of Vehicle
, not only one Car
, you may want to remove properties
from Vehicle
type and create a discriminated union of allowed Vehicles
.如果您有更多的Vehicle
变体,而不仅仅是一个Car
,您可能希望从Vehicle
类型中删除properties
并创建允许的Vehicles
的有区别的联合。 It is only my guess, since I'm not aware of any other requirements.这只是我的猜测,因为我不知道任何其他要求。
It is also worth knowing about excess-property-checks .还值得了解有关extra-property-checks 的信息。 It will disallow you to provide any other extra properties for literal argument.它将不允许您为文字参数提供任何其他额外属性。
If you put all your requirements and test cases into your question I believe you will get what you are looking for如果您将所有要求和测试用例都放入您的问题中,我相信您会得到您想要的
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.