函数中映射类型和枚举的 Typescript 类型推断为什么不起作用?

Typescript type inference with mapped type and enums in a function why not works?

我想不通,为什么这里的类型推断不起作用(见下面的代码)。

enum Vehicle {
  Car,
  Bus,
  Plane,
}

interface CarParams {
  carId: string;
}

interface BusParams {
  busId: string;
}

interface PlaneParams {
  planeId: string;
}

type Params = {
  [Vehicle.Bus]: BusParams;
  [Vehicle.Car]: CarParams;
  [Vehicle.Plane]: PlaneParams;
};

function showDriver<T extends Vehicle>(vehicle: T, params: Params[T] ): void {
// ...
  if (vehicle === Vehicle.Bus) {
    params.busId //<---- Property 'busId' does not exist on type 'CarParams | BusParams | PlaneParams'.
    // Type inference doesn't work here!
  }
}

showDriver(Vehicle.Bus, { busId: '' }) // <--- type inference works here!

in operator narrowing 可用,我们可以利用它来识别联合中的特定成员类型。

enum Vehicle {
  Car,
  Bus,
  Plane,
}

interface CarParams {
  carId: string;
}

interface BusParams {
  busId: string;
}

interface PlaneParams {
  planeId: string;
}

type Params = {
  [Vehicle.Bus]: BusParams;
  [Vehicle.Car]: CarParams;
  [Vehicle.Plane]: PlaneParams;
};

function showDriver<T extends Vehicle>(vehicle: T, params: Params[T]): void {
  // ...
  if ("busId" in params) {
    console.log(params.busId);
  }
  if ("carId" in params) {
    console.log(params.carId);
  }
  if ("planeId" in params) {
    console.log(params.planeId);
  }
}

showDriver(Vehicle.Bus, { busId: 'bus123' });
showDriver(Vehicle.Car, { carId: 'car123' });
showDriver(Vehicle.Plane, { planeId: 'plane123' });

插图

"use strict";
var Vehicle;
(function(Vehicle) {
  Vehicle[Vehicle["Car"] = 0] = "Car";
  Vehicle[Vehicle["Bus"] = 1] = "Bus";
  Vehicle[Vehicle["Plane"] = 2] = "Plane";
})(Vehicle || (Vehicle = {}));

function showDriver(vehicle, params) {
  // ...
  if ("busId" in params) {
    console.log(params.busId);
  }
  if ("carId" in params) {
    console.log(params.carId);
  }
  if ("planeId" in params) {
    console.log(params.planeId);
  }
}

showDriver(Vehicle.Bus, {
  busId: 'bus123'
});

showDriver(Vehicle.Car, {
  carId: 'car123'
});

showDriver(Vehicle.Plane, {
  planeId: 'plane123'
});


WYSIWYG => WHAT YOU SHOW IS WHAT YOU GET

不完全确定为什么它不起作用,但我认为可能是因为 Params 类型不是 JS 对象,TS 不支持这样的映射类型。我发现了它的其他细微限制,不幸的是,这让我重新构建了我的代码。 TS很强大,但是还在开发中,还不完善

无论如何,我在这里采取了一种略有不同的方法,似乎可以按您的预期工作,并允许您直接与枚举进行比较,而不必使用每种类型唯一的字段。

enum Vehicle {
  Car,
  Bus,
  Plane
}

interface CarParams {
  kind: Vehicle.Car;
  carId: string;
}

interface BusParams {
  kind: Vehicle.Bus;
  busId: string;
}

interface PlaneParams {
  kind: Vehicle.Plane;
  planeId: string;
}

type Params = CarParams | BusParams | PlaneParams;

function showDriver(params: Params): void {
  // ...
  if (params.kind === Vehicle.Bus) {
    params.busId = "1"; // exists
    params.planeId = "2"; // does not exist
  }
}

showDriver({
  kind: Vehicle.Bus,
  busId: "", // exists
  planeId: "" // does not exist
});