使用对象来区分联合类型

时间:2020-05-30 17:58:04

标签: typescript union-types

我正在尝试在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);
}

3 个答案:

答案 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);
}