【问题标题】:Typescript array.map doesn't distribute intersection types properlyTypescript array.map 没有正确分配交集类型
【发布时间】:2020-02-20 15:38:11
【问题描述】:

我有一个object[] & Tree[] 类型的数组,但arr.map(child => ...) 将孩子的类型推断为object 而不是object & Tree

有没有什么方法可以避免这种情况而不需要额外的转换?

值得注意的是Tree 扩展了object,但打字稿似乎没有意识到这一点并合并了交叉类型的两个部分。

编辑 - 最小可重现示例:

这是人为的,但基于我最近的另一个问题Transform a typescript object type to a mapped type that references itself

interface BasicInterface {
    name: string;
    children: object[];
}

function getBasic<T extends object>(input: T): BasicInterface {
    return input as BasicInterface;
}

export const basicTree = getBasic({
    name: 'parent',
    children: [{
        name: 'child',
        children: []
    }]
});

关键是下面的代码可以访问“basicTree”及其推断类型。对于这个例子,我定义了 BasicInterface,但实际上这是自动生成的,我还没有找到一种编程方式 生成递归接口。

我想将递归类型的子元素添加回原来的接口定义。

我正在尝试,而不是在代码中完全重新定义 BasicInterface,因为这可能是很多样板文件 用正确的递归定义“增强”基本树类型的定义。

但是在获取孩子的类型时,这会下降。或许有更简单的解决方案?

type RestoredInterface = typeof basicTree & {
    children: RestoredInterface[]
};

function getTree(basic: BasicInterface): RestoredInterface {
    return basic as RestoredInterface;
}

const restoredTree = getTree(basicTree);

const names = restoredTree.children.map(child => child.name);

【问题讨论】:

  • 函数的交集被解释为overloads,所以对arr.map()的调用很可能被认为是调用了第一个重载;即object[]map 方法。我想知道为什么类型不是(object &amp; Tree)[]Tree[]?十字路口在哪里?您能否提供minimal reproducible example 以便有人可以建议您?
  • 啊,我明白了,谢谢。为了清楚起见,我将用一个示例更新原始问题
  • basicTree 的推断类型只是BasicInterface,并且您的交集不会导致类似object[] &amp; Tree[] 的任何内容;相反,它只是object[] &amp; OtherThingsThatAreNotArrays。您确定此示例重现了您的问题吗?
  • interface RestoredInterface extends BasicInterface { children: RestoredInterface[] } 可能会做你想做的事?请注意,我认为上面的示例中有一个错字,因为您在我希望看到 RestoredInterface[] 的地方有 RestoredInterface
  • 在上面,您是否尝试过将RestoredInterface 的定义更改为interface RestoredInterface extends BasicInterface { children: RestoredInterface[] }?那应该可以解决问题。如果这不能满足您的需求,请编辑示例代码以反映这一点。

标签: typescript intersection array-map mapped-types


【解决方案1】:

我找到了一个奇怪的解决方案。只需更改声明中的顺序即可。这很奇怪,但它有效:

type RestoredInterface = {
    children: RestoredInterface[]
} & typeof basicTree;

编辑:这是explanation

更好的解决方案可能是这样的:

type RestoredInterface = Omit<typeof basicTree, 'children'> & {
    children: RestoredInterface[]
};

Playground

【讨论】:

  • 谢谢,这很好用。我还提出了一个解决方案,但是当typeof basicTree 更复杂时,这是唯一合适的解决方案,例如如果它本身是一个联合类型,它没有静态已知的键并且不能使用扩展
【解决方案2】:

根据 jcalz 的观察,实际上可以简单地扩展原始界面。我很困惑,因为它是以编程方式定义的,但如果你先命名它,那不是问题:

type BasicTreeInterface = typeof basicTree;

interface RestoredInterface extends BasicTreeInterface {
    children: RestoredInterface[]
};

const restoredTree = getTree(basicTree);

const names = restoredTree.children.map(child => {
    // Child is of type RestoredInterface
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-21
    • 2023-01-29
    • 1970-01-01
    • 2019-06-24
    • 2020-04-03
    • 2021-10-18
    • 1970-01-01
    • 2020-03-11
    相关资源
    最近更新 更多