是否可以在 TypeScript 中创建严格的'A or B'类型?



我遇到了一个键入React组件的问题,这是我以前从未遇到过的。我已经简化了下面的问题。

interface Circle {
kind?: "circle";
radius: number;
}

interface Square {
kind: "square";
sideLength: number;
}

type Shape = Circle | Square;
const shape: Shape = {
sideLength: 7,
radius: 7,
};

指向包含上述

的TypeScript Playground的链接在上面的例子中,我希望shape变量声明在TypeScript中抛出一个错误,因为Circle和Square都没有一个sideLength和一个radius。定义的对象既不是圆形也不是正方形,所以在我看来,它不应该是一个有效的形状。

是否可以这样定义类型,使下列项目是有效的或错误的(如标记的)?

// Valid
const shape: Shape = {
kind: 'circle',
radius: 7,
};
// Valid
const shape: Shape = {
radius: 7,
};
// Valid
const shape: Shape = {
kind: 'square',
sideLength: 7,
};
// Error
const shape: Shape = {
sideLength: 7,
radius: 7,
};
// Error
const shape: Shape = {
sideLength: 7,
};
// Error
const shape: Shape = {
kind: 'square',
radius: 7,
};
// Error
const shape: Shape = {
kind: 'circle',
sideLength: 7,
};

编辑:

为了进一步澄清,在我的用例中,kind在Circle上是可选的。对于那些熟悉React的人来说,我试图解决的实际问题是围绕样式组件暴露的as属性。我想要一个组件接受可选的as道具,这将允许用户将组件(默认为button)更改为链接(a)。如果用户指定了as="a",那么我希望TypeScript能够比较用户是否尝试在现在的链接(例如disabled)上使用特定于按钮的道具。as道具是可选的,因为我不希望所有实现者都被要求传递它。在我上面的简化示例中,as类似于kind,这就是为什么kind是可选的。

注意,您已经将kind属性定义为可选属性,因此,如果您创建的形状对象中只有radius属性仍然有效,那么circle:

看这个东西

const shape: Shape = {
sideLength: 7,
radius: 7,
};

这是一个有一个额外属性的有效圆。

所以在某些情况下你说,你应该把kind属性作为一个必需的属性:

interface Circle {
kind: "circle";
radius: number;
}

interface Square {
kind: "square";
sideLength: number;
}

type Shape = Circle | Square;
const shape2: Shape = {
radius: 7,//Error
};

PlaygroundLink

最新更新