在TypeScript中为装配线建模

bbuxkriu  于 2023-02-10  发布在  TypeScript
关注(0)|答案(3)|浏览(101)

我有一个脚本,它的工作原理有点像流水线,它从一个字典开始,字典中的对象只有一个属性,然后在每一步之后再添加一个属性。
我从普通的JS开始,现在把它转换成TS。
我现在已经将其建模为一个Typescript接口,该接口具有一个强制属性和许多可选属性:

interface CarBatch {
  [key: string]: {
    part1: string;
    part2?: string[];
    part3?: SteeringWheel;
    part4?: string;
    part5?: string;
    part6?: string;
  }
}

然而,Typescript对此抱怨了很多,因为访问这些可选属性总是产生“Object is possibly 'undefined'”。
我试着使用一个基本接口和extends,但这很困难,因为字典,因为我的汇编步骤总是从一种类型开始,并需要在中间将其修改为另一种类型。
正确的建模方法是什么?

y4ekin9u

y4ekin9u1#

根据Ali的评论,这可以通过在console.log中添加问号来处理:
console.log(carBatch?.['porsche']?.part4)

ukdjmx9f

ukdjmx9f2#

您的代码似乎松散地遵循了builder模式。因此,您可以这样键入:

function addStage<P extends Record<string, unknown>, K extends string, V>(
  previous: P, key: K, value: V
): P & { [key in K]: V } {
  return {
    ...previous,
    [key]: value,
  };
}

// Usage
const stage1 = addStage({}, 'part1', 1);
//    ^?
const stage2 = addStage(stage1, 'part2', 'value');
//    ^?
const stage3 = addStage(stage2, 'part3', [1, 2, 3]);
//    ^?

typescript Playground链接

kokeuurv

kokeuurv3#

您可以充分利用内置的实用程序类型Pick
首先,让我们将一个完整的Car声明为一个单独的接口:

interface Car {
  part1: string;
  part2: string[];
}

为了简短起见,我省略了part3part6,但请放心,这种方法可以很好地扩展。
未完工的汽车表示为类型PartialCar,其中有一个泛型参数K,用于定义哪些键必须已经存在:

type PartialCar<K extends keyof Car> = Pick<Car, K>;

由于CarBatch可能包含未完成的汽车,因此我们将其设置为泛型:

interface CarBatch<C> {
  [key: string]: C
}

注意,没有必要限制C类型。
让我们看看如何创建一批只分配了part1的汽车:

function startBatch(): CarBatch<PartialCar<'part1'>> {
  return {
    'porsche': {
      part1: 'one'
    }
  }
}

要将新部件part2添加到所有汽车,我们接受任何未完成的汽车类型C,并返回包含更多成品汽车类型C & PartialCar<'part2'>的批次:

function addPart2<C>(batch: CarBatch<C>): CarBatch<C & PartialCar<'part2'>> {
  const outputBatch: CarBatch<C & Pick<Car, 'part2'>> = {};
  for (const key of Object.keys(batch)) {
    outputBatch[key] = {
      ...batch[key],
      part2: ['left', 'right'],
    };
  }
  return outputBatch;
}

此函数的作用与C的类型无关,但您可以轻松地对其进行限制。例如,如果part2的分配取决于part1的存在,则使用C extends PartialCar<'part1'>
一批成品汽车当然是一辆CarBatch<Car>

function printBatch(batch: CarBatch<Car>) {
  console.log(batch);
}

为了证明这一切都是可行的:

let batch = startBatch();
let finishedBatch = addPart2(batch);
printBatch(finishedBatch);

Playground链接

相关问题