如何键入一个转换输入对象某些属性的函数

How to type a function that transforms some properties of an input object

有谁知道如何输入只有部分键是 known/relevant 并且其中一个已知键是可选的转换函数?例如

const transform = <T extends BaseAkpiDto>(akpiDTO: T) => {
  const { startDate, periodData, ...akpiBase } = akpiDTO;
  const withMoments = {
    ...akpiBase,
    startDate: moment.utc(startDate),
  };

  if (!periodData) {
    return withMoments;
  }

  return {
    ...withMoments,
    lineData: akpiDtoToLineData(withMoments.startDate, periodData),
  };
};

interface BaseAkpiDto {
  startDate: string;
  endDate: string;
  periodData?: PeriodDto[];
}

const test: WithPeriodData = akpiDTOtoAkpiData({
  id: 1,
  name: 'my name',
  startDate: '2019',
  periodData: [] as PeriodDto[],
});

interface WithPeriodData {
  id: number;
  name: string;
  startDate: Moment;
  lineData: Period[];
}

如果(且仅当)输入中有 lineData 属性 时,我无法让 return 类型包含 lineData 属性 :(

Typescript 使用以下消息向我的 test 变量投诉:

Property 'lineData' is missing in type 'Pick<{ id: number; name: string; startDate: string; periodData: PeriodDto[]; }, "id" | "name"> & { startDate: Moment; endDate: Moment; }' but required in type 'WithPeriodData'.

函数 transform 具有条件行为。查看控制流,它可以 return 或包含 lineData 或不包含的对象。因此你不能分配 return 这是一个联合 IHaveLineData | IDoNotHaveLineDataIHaveLineData 因为 return 只是更宽的类型。假设您想将 string | number 的 smth 分配给 number,原因与您不能这样做的原因相同。

为确保获得所需的结构,您需要附加额外的控制流以确保类型。所以只是:

// at this level test is infered as with or without lineData
const test= akpiDTOtoAkpiData({
  id: 1,
  name: 'my name',
  startDate: '2019',
  periodData: [] as PeriodDto[],
});

if ('lineData' in test) {
  // here test is precisely the type with lineData
}