Typescript 接口一个字段类型依赖于另一个使用接口交集'&'的字段值

Typescript interface a field type depend on another field value using interface intersection '&'

我试图根据字段 'type' 的值推断 'data' 类型,但似乎我没有正确地做到这一点... 我想使用交集运算符来避免多行条件。

查看下面的代码:

interface IActivityNote {
  type: "note";
  data: {
    title: string;
    content?: string;
  };
}
interface IActivityArchive {
  type: "archive";
  data: { reason: string };
}
type TActivityData = IActivityNote | IActivityArchive;

interface IActivityBase {
  id: string;
  ownerId: string;
}
type TActivity = IActivityBase & TActivityData;

interface IActivityServerBase {
  id: string;
  owner: string;
}
type TActivityServer = IActivityServerBase & TActivityData;

const mapToActivityServer = (activity: TActivity): TActivityServer => ({
  id: activity.id,
  owner: activity.ownerId,
  type: activity.type,
  data: activity.data
});

为什么TS不自己搞定?我是否必须在函数中放置条件以根据类型值指定数据结构?

转载于此:https://codesandbox.io/s/typescript-infering-type-value-with-interface-intersection-svdgsd?file=/src/index.ts

基本上我想要的类型是:

{
  id: string
  owner: string
  type: 'note'
  data: { title: string; content?: string }
}

// OR

{
  id: string
  owner: string
  type: 'archive'
  data: { reason: string }
}

但是使用智能交集类型可以避免为每个新的 'type' 值复制我想要实现的具有不同 'data' 结构的整个对象类型。

这是 TypeScript 中的一个已知错误,请参阅 microsoft/TypeScript#33654. Prior to TypeScript 3.5 introduced smarter union type checking there would have been no chance of this working, because the compiler would not bother to try to relate the type it infers for your output with the annotated return type. The PR at microsoft/TypeScript#30779 changed things so that now there is some attempt to expand out object types with union properties into unions of object types, and the PR at microsoft/TypeScript#36663 显然可以更好地处理交集,但显然这些更改都不足以使您的代码正常工作。

尚不清楚何时或是否会修复此错误。目前,解决方法 suggested in ms/TS#33654 是 spread/destructure,这样它确实会触发“更智能的联合类型检查”。在您的情况下,它可能看起来像这样:

const mapToActivityServer = (activity: TActivity): TActivityServer => {
    const { ownerId: owner, ...act } = activity;
    return { ...act, owner }; // no error now
} 

Playground link to code