我正在将一些现有的 JS 代码转换为 TS,我们使用了一种模式,我不知道如何用 typescript 正确表达:
function getVehicles({
brandFields = false,
ownerFields = false,
maintenanceFields = false
} = {}) {
// building and executing some SQL
}
我们的存储库严重依赖这种模式,我们将获取成本高昂的数据放在一个标志后面,并且一个函数可以拥有多个这样的标志。
现在,尝试输入返回值的不同部分是一项工作,但效果很好:
type Vehicle = { id: dbId, manufactureDate: Date, color: string }
type VehicleBrand = { brandName: string, brandCountry: string }
type VehicleOwner = { owner: Person }
type VehicleMaintenance = { maintenance: { date: Date, place: string, operation: string } [} }
function getVehicles({
brandFields = false,
ownerFields = false,
maintenanceFields = false
} = {}): (Vehicle & VehicleBrand & VehicleOwner & VehicleMaintenance) [] {
// building and executing some SQL
}
但我想让返回类型更精确。 This SO question建议进行重载,但由于排列的数量,在这种情况下这是不切实际的。
所以我认为留给我的唯一选择是使用泛型和条件类型,大致如下:
// With only one parameter for simplicity
function getVehicles<
Brand extends boolean
>({
brandFields: Brand = false
} = {}): (
Vehicle &
(Brand extends true ? VehicleBrand : {})
) [] {
// building and executing some SQL
}
但我还没有找到一种方法,让 typescript 满意,同时在所有情况下返回尽可能窄的类型。
getVehicles() // should return Vehicle
getVehicles({ brandFields: false }) // should return Vehicle
getVehicles({ brandFields: true }) // should return Vehicle & VehicleBrand
getVehicles({ brandFields: boolean }) // should return Vehicle & (VehicleBrand | {})
我最接近的是这个签名,但它太宽松了:
function getVehicles<
Brand extends boolean
>({
brandFields: Brand | false = false // <-- union to avoid an error ...
} = {}): (
Vehicle &
(Brand extends true ? VehicleBrand : {})
) [] {
// building and executing some SQL
}
getVehicles({ brandFields: true }) // but returns Vehicle & (VehicleBrand | {}) in this case
在当前 typescript 的限制下这是否可以实现?
最佳答案
您可以通过conditional types来实现这一点,像这样:
type Vehicle<O extends OptionsFlags> = VehicleBase &
(O extends { brandFields: true }
? VehicleBrand
: O extends { brandFields: false | undefined }
? {}
: VehicleBrand | {}) &
(O extends { ownerFields: true }
? VehicleOwner
: O extends { ownerFields: false | undefined }
? {}
: VehicleOwner | {}) &
(O extends { maintenanceFields: true }
? VehicleMaintenance
: O extends { maintenanceFields: false | undefined }
? {}
: VehicleMaintenance | {});
interface OptionsFlags {
brandFields?: boolean;
ownerFields?: boolean;
maintenanceFields?: boolean;
}
interface VehicleBase {
id: dbId;
manufactureDate: Date;
color: string;
}
interface VehicleBrand {
brandName: string;
brandCountry: string;
}
interface VehicleOwner {
owner: Person;
}
interface VehicleMaintenance {
maintenance: { date: Date; place: string; operation: string }[];
}
function getVehicles<O extends OptionsFlags>({
brandFields = false,
ownerFields = false,
maintenanceFields = false,
}: O = {} as O): Vehicle<O>[] {
// ...
}
getVehicles({ brandFields: true }) // return type is Vehicle<{ brandFields: true }>[]
但是...
根据您如何使用它,您可能会发现定义 Vehicle
更有帮助。像这样输入,允许每个 Vehicle
子类型解析为可能具有可选属性的单个接口(interface):
type Vehicle<O extends OptionsFlags> = VehicleBase &
(O extends { brandFields: true }
? VehicleBrand
: O extends { brandFields: false | undefined }
? {}
: Partial<VehicleBrand>) &
(O extends { ownerFields: true }
? VehicleOwner
: O extends { ownerFields: false | undefined }
? {}
: Partial<VehicleOwner>) &
(O extends { maintenanceFields: true }
? VehicleMaintenance
: O extends { maintenanceFields: false | undefined }
? {}
: Partial<VehicleMaintenance>);
Vehicle<{ brandFields: boolean }>
那么就相当于:
{
id: dbId;
manufactureDate: Date;
color: string;
brandName?: string;
brandCountry?: string;
}
关于Typescript - 如何基于带有默认值的可选 bool 参数执行条件返回类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68181933/