如何让 TS 使用递归判别联合进行类型推断?

How to get TS to do type inference with recursive discriminated unions?

提问人:kohloth 提问时间:11/16/2023 更新时间:11/16/2023 访问量:20

问:

我可以在 TS 中使用什么机制让 TS 使用递归判别联合进行类型推断?

给出下面的例子:


interface Circle {
    type: 'circle';
    radius: 3;
}

interface Square {
    type: 'square';
    sides: 4;
}

interface Bag {
    type: 'bag';
    color: 'green';
    children: AnyItem[];
}

type AnyItem = Circle | Square | Bag;

interface CircleConstructorParams {
    type: 'circle';
}

interface SquareConstructorParams {
    type: 'square';
}

interface BagConstructorParams {
    type: 'bag';
    children: AnyConstructorParams[];
}

type AnyConstructorParams = CircleConstructorParams | SquareConstructorParams | BagConstructorParams;

function getItem(itemConstructorParams: AnyConstructorParams) {
    if (itemConstructorParams.type === 'circle') {
        const circle: Circle = {
            type: 'circle',
            radius: 3,
        };
        return circle;
    } else if (itemConstructorParams.type === 'square') {
        const square: Square = {
            type: 'square',
            sides: 4,
        };
        return square;
    } else if (itemConstructorParams.type === 'bag') {
        const bag: Bag = {
            type: 'bag',
            color: 'green',
            children: itemConstructorParams.children.map(child => {
                return getItem(child);
            })
        };
        return bag;
    }
    throw new Error('Invalid');
}

const circle = getItem({ type: 'circle' });
console.log(circle.radius);

const square = getItem({ type: 'square' });
console.log(square.sides);

const nested = getItem({
    type: 'bag',
    children: [
        { type: 'square', },
        { type: 'circle', },
        {
            type: 'bag',
            children: [
                { type: 'square' },
                { type: 'circle' },
            ]
        },
    ],
});
console.log(nested.children[2].children[1].radius);

我收到以下错误:

Property 'radius' does not exist on type 'Circle | Square | Bag'.
  Property 'radius' does not exist on type 'Square'.
Property 'sides' does not exist on type 'Circle | Square | Bag'.
  Property 'sides' does not exist on type 'Circle'.
Property 'children' does not exist on type 'Circle | Square | Bag'.
  Property 'children' does not exist on type 'Circle'.

鉴于我使用了文字成员、类型保护和类型化返回对象,我希望 TS 能够从每个嵌套的“Item 构造函数”推断每个嵌套“Item”的类型。

以这种方式使用 TS 无法推断类型的原因是什么,正确的方法是什么,同时避免执行以下操作:

console.log((((nested as Bag).children[2] as Bag).children[1] as Circle).radius);

TypeScript 递归 可区分并集

评论


答: 暂无答案