我正在尝试在TypeScript中创建联合类型,其中区分符是嵌套对象上的值,而不是直接在类型上的原始值。我正在使用从API返回的对象,因此无法更改返回的数据结构。
可以在TypeScript中实现这种功能,而无需求助于用户定义的类型防护吗?
这是一个简化的示例:
type SquareIdentifier = {
type: "square";
};
type CircleIdentifier = {
type: "circle";
};
type SquareShape = {
identifier: SquareIdentifier;
sideLength: number;
};
type CircleShape = {
identifier: CircleIdentifier;
diameter: number;
};
type Shape = SquareShape | CircleShape;
// assume we have been given a variable `x` of Shape
const x = ({} as any) as Shape;
// at this point, x.identifier is considered a SquareIdentifier | CircleIdentifier
if (x.identifier.type === "square") {
// at this point, x.identifier is considered a SquareIdentifier
// however, x is still considered a Shape, not a SquareShape, which is the only Shape to contain a ShapeIdentifier
// error here is:
// "Property 'sideLength' does not exist on type 'Shape'"
// "Property 'sideLength' does not exist on type 'CircleShape'"
console.log(x.sideLength);
}
答案 0 :(得分:2)
是的,有可能。您需要使用user defined type guards
例如这样的
if (isSquareShape(x)) {
console.log(x.sideLength);
}
function isSquareShape(value: Shape): value is SquareShape {
return value.identifier.type === 'square';
}
答案 1 :(得分:0)
type guards可以满足您的需求:
type SquareIdentifier = {
type: "square";
};
type CircleIdentifier = {
type: "circle";
};
type SquareShape = {
identifier: SquareIdentifier;
sideLength: number;
};
type CircleShape = {
identifier: CircleIdentifier;
diameter: number;
};
type Shape = SquareShape | CircleShape;
const isSquareShape = (x: any): x is SquareShape => {
return x.type && x.type === 'sqaure';
}
const testFunction = (x: any) => {
if (isSquareShape(x)) {
const y = x.sideLength; // this now works, because typescript 'knows' we have a square shape
}
}
函数isSquareShape
允许打字稿确定某个值的类型为SquareShape
,因此一旦我们有了将值通过此检查传递的代码(在这种情况下,if (isSquareShape(x))
)我们可以像访问SquareShape
一样访问该值,而不会出现类型错误。
答案 2 :(得分:0)
在您的示例中,我将使用in
运算符类型保护:
type Shape = SquareShape | CircleShape;
// assume we have been given a variable `x` of Shape
const x = ({} as any) as Shape;
if ('sideLength' in x) {
// x is inferred as SquareShape
console.log(x.sideLength);
}