首页 > 解决方案 > 鉴于这种类型安全的方法接受一个参数,您能否将其推广到 N 个参数同时保持类型安全?

问题描述

背景:

这是对前面两个问题的后续:1 , 2

接口Extendable在类型T上是通用的,并且具有方法extend接受U类型的参数并返回V类型的参数:

interface Extendable<T> {
  extend<U, V>(x: U): V
}

方法extend具有以下约束:

Interface Extendable在下面更新以反映这些约束:

interface Extendable<T> {
  extend<U extends (T extends U ? unknown : T)>(x: U): U extends T ? T : U
}

Interface Extendable测试如下:

interface A { a: string }
interface B extends A { b: string }
interface C extends B { c: string }
interface D extends A { d: string }
interface E { e: string }

declare let a: A, b: B, c: C, d: D, e: E
declare let t: Extendable<B>

t.extend(a) // return type A
t.extend(b) // return type B
t.extend(c) // return type B
t.extend(d) // error - D is not assignable to B
t.extend(e) // error - E is not assignable to B

现在事实证明,我正在构建一个类型化的 SQL 查询构建器,并且查询是可扩展的。以下是倒排查询类型层次结构:

+Root
+---Filter
|   +---Select
|   +---Update
|   \---Delete
\---Insert

查询类型之间的继承是通过鸭子类型隐含的,而不是显式扩展。

Root 可分配给 Filter 和 Insert。过滤器可分配给选择、更新和删除。

您从查询类型 Root 开始。如果您构造 WHERE 子句,则新的查询类型将变为 Filter。如果随后构造 DELETE 子句,则新查询类型将变为 Delete。

接口如下。

interface Root extends Extendable<Root> {
  where(): Filter
  select(): Select
  insert(): Insert
  update(): Update
  delete(): Delete
}
interface Filter extends Extendable<Filter> {
  where(): Filter
  select(): Select
  update(): Update
  delete(): Delete
}
interface Select extends Extendable<Select> {
  where(): Select
  select(): Select
}
interface Update extends Extendable<Update> {
  where(): Update
  update(): Update
}
interface Delete extends Extendable<Delete> {
  where(): Delete
  delete(): Delete
}
interface Insert extends Extendable<Insert> {
  insert(): Insert
}

查询类型测试如下:

declare let root: Root
declare let filter: Filter
declare let select: Select
declare let insert: Insert

filter.extend(root) // return type Filter
filter.extend(filter) // return type Filter
filter.extend(select) // return type Select
filter.extend(insert) // error - Insert is not assignable to Filter

Extendable 接口的原始约束保证了这两个属性:

问题:

我想添加一个额外的类型安全重载的扩展,它接受多个查询参数,例如extend(...args)

它将使以下两行等效:

a.extend(b).extend(c).extend(d)
a.extend(b, c, d)

我不知道如何以类型安全的方式编写重载。可能吗?

如果不可能,有没有办法为两个参数编写重载?对于三个论点?你能把这个过程概括为 N 个参数吗?

标签: typescriptgenerics

解决方案


推荐阅读