Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 是否可以声明一个接受给定类型超类的函数?_Typescript_Typescript Typings - Fatal编程技术网

Typescript 是否可以声明一个接受给定类型超类的函数?

Typescript 是否可以声明一个接受给定类型超类的函数?,typescript,typescript-typings,Typescript,Typescript Typings,我正在为一个Javascript库写作 我有一个在类型T上是泛型的接口。它有一个带有参数的函数,该参数应该具有类型(T |子类(T)|超类(T)) 该界面当前看起来如下所示: interface Query<T> { extend(arg: T): T } 我想将类型安全性添加到extend(),这样,如果T是当前的查询生成器类型,则只接受T类型的查询、T的超类和T的子类 例如,这将阻止您使用仅在Select查询中有意义的方法扩展Insert查询,例如 sq.insert().

我正在为一个Javascript库写作

我有一个在类型T上是泛型的接口。它有一个带有参数的函数,该参数应该具有类型(T |子类(T)|超类(T))

该界面当前看起来如下所示:

interface Query<T> {
  extend(arg: T): T
}
我想将类型安全性添加到
extend()
,这样,如果T是当前的查询生成器类型,则只接受T类型的查询、T的超类和T的子类

例如,这将阻止您使用仅在Select查询中有意义的方法扩展Insert查询,例如

sq.insert().extend(sq.limit()) // should throw type error
上述方法调用中的类型包括:

SelectInsertUpdateDeleteBuilder.extend(
  SelectUpdateDeleteBuilder,
  SelectInsertUpdateDeleteBuilder
)
InsertBuilder.extend(SelectBuilder)

我可以使
Query.extend()
只接受可分配给
T
或可分配给
T
的参数。也就是说,要么是超类型,要么是子类型。它使用(就像这些事情经常做的那样):

不确定
查询的实现
;希望你能处理好


祝你好运

此库的当前定义表单npm在语法上无效:(我现在正在添加打字。npm上的打字是古老的。你可以在我从你的分支得到定义的地方找到我正在处理的打字。但是我看不出问题。你的第一个示例有效,而在你的第二个示例中我得到了一个类型错误。什么不起作用?如果当前的实现对示例有效,这只是偶然的。correct逻辑是我在问题中描述的,但我不知道如何实现正确的逻辑。这很聪明。谢谢,这很好!我的库的extend()函数实际上接受一系列查询,所以现在唯一可能不安全的情况是如果两个参数的类型不兼容,例如sq.extend(sq.insert(),sq.limit())。您是否建议将extend限制为仅一个参数以保持类型安全?或者是否有条件类型魔术可以解释这一点?我仍在尝试解析您的答案,我最终实现了extend的类型要求(…args)方法:所有参数必须具有相同的谱系,没有分叉,返回类型是最具体的参数类型。我不知道是否可以使用可变数组参数声明此函数,但应该可以枚举到固定数字的算术。此解决方案的一个问题是返回类型成为参数t类型。是否可以使返回类型成为基类型和参数类型中更具体的类型?使用另一个问题中的内容进行更新
interface Query<T> {
  extend<U extends (T extends U ? unknown : T)>(x: U): U;
}
class A { a: string = "a" }
class B extends A { b: string = "b" }
class C extends B { c: string = "c" }

class D extends A { d: string = "d" }
class E { e: string = "e" }

declare let a: A;
declare let b: B;
declare let c: C;
declare let d: D;
declare let e: E;

declare let qb: Query<B>;
qb.extend(a); // okay, B extends A
qb.extend(b); // okay, B extends B
qb.extend(c); // okay, C extends B
qb.extend(d); // error, D not assignable to B
qb.extend(e); // error, E not assignable to B
qb.extend(Math.random() < 0.5 ? a : e); // okay, B extends A | E
type NotExtendsAll<T, U> = (U extends any ? [T] extends [U] ? never : unknown : never)
type AbsorbUnion<T> = [T] extends [infer U] ? U extends any ?
  NotExtendsAll<U, T> extends never ? U : never : never : never
type Absorb<T extends any[]> = AbsorbUnion<{ [K in keyof T]: [T[K]] }[number]>[0];

type AsArray<T> = [T] extends [any[]] ? T : never;    
interface Query<T> {
  extend<U extends AsArray<{ [K in keyof U]: T extends U[K] ? unknown : T }>>(
  ...x: U
  ): Absorb<U> extends never ? T : Absorb<U>;
}
qb.extend(a, a, a); // okay, returns type A
qb.extend(b, a, b, b, a); // okay, returns type B 
qb.extend(a, b, c, b, a); // okay, returns type C
qb.extend(); // okay, returns type B