在Typescript中基于另一个函数参数使一个函数参数为必选/可选



我是typescript的新手,正在尝试为接受第三个参数作为可选参数的函数实现类型检查。然后根据另一个函数实参,决定是否使用第三个实参。

我让它是可选的,但是:

  1. 我得到一个错误。
  2. 即使我没有得到错误,我想知道我是否可以根据另一个(vehicleType)在该参数(trailer)上切换所需/可选标志。

下面是我为这个场合准备的一个例子:

enum VehicleType {
Car,
Pickup
}
type Vehicle = {
weight: number;
length: number;
};
type Trailer = {
weight: number;
length: number;
};
function vehicle(
vehicleType: VehicleType,
vehicle: Vehicle,
trailer?: Trailer
) {
switch (vehicleType) {
case VehicleType.Car:
return `${vehicle.length} ${vehicle.weight}`;
case VehicleType.Pickup:
return `${vehicle.length + trailer.length} ${
vehicle.weight + trailer?.weight
}`;
}
}
对于这段代码,我得到两次相同的错误:

对象可能'未定义'。对于trailer.对象

如果类型是Pickup,是否有一种方法可以强制编译器要求trailer,而不是当类型是Car时?

我从问题中得出,如果vehicleTypePickup,trailer是必需的参数。

如果是,问题是TypeScript不知道;据它所知,vehicle(VehicleType.Pickup, someVehicle)(没有trailer)是完全有效的。

可以使用函数重载告诉它有效的参数的具体组合;它不能完全解决问题,但它使我们接近:

function vehicle(vehicleType: VehicleType.Car, vehicle: Vehicle): string;
function vehicle(vehicleType: VehicleType.Pickup, vehicle: Vehicle, trailer: Trailer): string;
function vehicle(vehicleType: VehicleType, vehicle: Vehicle, trailer?: Trailer): string {
switch (vehicleType) {
case VehicleType.Car:
return `${vehicle.length} ${vehicle.weight}`;
case VehicleType.Pickup:
assertNotNullish(trailer);
return `${vehicle.length + trailer.length} ${vehicle.weight + trailer.weight}`;
}
}

只有前两个是公共签名;第三个是实现签名,它只是实现签名,不会被其他代码看到。

现在的问题是,在实现代码中,它仍然抱怨trailer可能是undefined,即使你知道(从过载签名)它不会。有两种方法可以解决这个问题:

  • 非空断言操作符,为后缀!
  • 显式断言

这是非空版本,当使用trailer时,注意!.之前:

function vehicle(vehicleType: VehicleType.Car, vehicle: Vehicle): string;
function vehicle(vehicleType: VehicleType.Pickup, vehicle: Vehicle, trailer: Trailer): string;
function vehicle(vehicleType: VehicleType, vehicle: Vehicle, trailer?: Trailer): string {
switch (vehicleType) {
case VehicleType.Car:
return `${vehicle.length} ${vehicle.weight}`;
case VehicleType.Pickup:
return `${vehicle.length + trailer!.length} ${vehicle.weight + trailer!.weight}`;
}
}

操场上联系

保证TypeScript知道trailer不会是undefined。(如果我们错了,我们将在运行时得到一个"无法读取属性' length ' of null"的错误)。

可以工作,但是许多人不喜欢代码中那种微妙的断言(包括我)。另一个选择是有一个实用函数,你可以使用它来显式地记录你的断言:

function assertNotNullish<T>(value: T | null | undefined): asserts value is T {
if (value ?? null === null) {
throw new Error(`Got null/undefined value where non-null/non-undefined value expected`);
}
}

函数告诉打印稿,如果它完成没有抛出异常,我们传递给它的价值不是nullundefined。然后我们像这样使用它:

function vehicle(vehicleType: VehicleType.Car, vehicle: Vehicle): string;
function vehicle(vehicleType: VehicleType.Pickup, vehicle: Vehicle, trailer: Trailer): string;
function vehicle(vehicleType: VehicleType, vehicle: Vehicle, trailer?: Trailer): string {
switch (vehicleType) {
case VehicleType.Car:
return `${vehicle.length} ${vehicle.weight}`;
case VehicleType.Pickup:
assertNotNullish(trailer);
return `${vehicle.length + trailer.length} ${vehicle.weight + trailer.weight}`;
}
}

操场上联系

我建议不要试图处理使第三个参数有条件为空的问题,而是在内部处理它。抛出一个异常,或者结合Nullish Coalescing操作符??

function vehicle(
vehicleType: VehicleType,
vehicle: Vehicle,
trailer?: Trailer
) {
switch (vehicleType) {
case VehicleType.Car:
return `${vehicle.length} ${vehicle.weight}`;
case VehicleType.Pickup:
return `${vehicle.length + (trailer?.length ?? 0)} ${
vehicle.weight + (trailer?.weight ?? 0)
}`;
}
}

这在所有情况下都有效

console.log(vehicle(VehicleType.Car, {weight:100, length:20}))
console.log(vehicle(VehicleType.Pickup, {weight:100, length:20}, {weight:10, length:5}))
console.log(vehicle(VehicleType.Pickup, {weight:100, length:20}))

操场上联系

如果您更喜欢异常路由,检查null的行为意味着您不再从TS

获得可能的null警告。
function vehicle(
vehicleType: VehicleType,
vehicle: Vehicle,
trailer?: Trailer
) {
switch (vehicleType) {
case VehicleType.Car:
return `${vehicle.length} ${vehicle.weight}`;
case VehicleType.Pickup:
if(!trailer){
throw "Trailer must be specified when VehicleType is Pickup"
}
return `${vehicle.length + trailer.length} ${
vehicle.weight + trailer.weight
}`;
}
}

操场上联系

相关内容

  • 没有找到相关文章

最新更新