如何采用任何构造函数类型并将其转换为接受相同参数的函数类型?

丹尼尔·德·安德拉德·瓦雷拉

考虑下面的代码,我创建了一个类,该类具有一个构造函数,该构造函数接收具有通用类型的参数,该参数用于定义第二个参数接收的参数的类型,在以下情况下,回调函数的参数为MouseEvent,因为第一个参数的值:

class MyClass<T extends keyof HTMLElementEventMap>{
    constructor(tagName: T, lister: (ev: HTMLElementEventMap[T]) => any) { }
}

new MyClass("click", ev => { })
//                   ^^ (parameter) ev: MouseEvent

但是,如果我创建一个函数,其其余参数的类型为ConstructorParameters <typeof MyClass>,则第二个参数将解析为回调参数的MouseEvent类型。 Event | UIEvent | AnimationEvent | MouseEvent | FocusEvent | DragEvent | ErrorEvent | PointerEvent | ... 6 more ... | ClipboardEvent

function myFunction(...args: ConstructorParameters<typeof MyClass>) {}

myFunction("click", ev => { })
//                  ^^ (parameter) ev: Event | UIEvent | AnimationEvent | MouseEvent | FocusEvent | DragEvent | ErrorEvent | PointerEvent | ... 6 more ... | ClipboardEvent

如何在不重写myFunction函数类型的情况下为回调参数获取正确的类型

是否可以?

贾卡尔兹

您想要说的是“采用任何构造函数类型并将其转换为接受相同参数函数类型”。


一个问题是TypeScript的类型系统没有一种很好的方式来表达适用于泛型函数的“可调用或可构造对象的参数” 如果您有类似的功能

function foo<T>(x: T, y: T): void { }

并尝试获取其参数列表,则通用参数T将替换为其约束在这种情况下,T不受约束,因此具有以下隐式约束unknown

type FooParams = Parameters<typeof foo>;
// type FooParams = [x: unknown, y: unknown]

TypeScript没有正确的通用类型来表示通用函数的参数列表。通用函数在调用签名上具有其通用类型参数。但是像这样的元组类型[x: unknown, y: unknown]没有调用签名,并且不能采用泛型类型参数:

// Not valid TS, do not use this:
type FooParams = <T>[x: T, y: T];

为了表示这一点,TypeScript将需要像microsoft / TypeScript#17574中所要求的任意通用值类型之类的东西但是它没有这些。


好的,所以不用担心元组类型,也许我们可以自动将一种泛型函数类型转换为另一种。再次不幸的是,该语言没有正确的类型操作符来执行此操作。为了捕获泛型函数及其类型参数之间的关系,TypeScript可能需要像microsoft / TypeScript#1213所要求的“高级类型”之类的东西,但是它也不具有这些。


在TypeScript 3.4之前,我会说我们将完全陷入困境。但是Typescript 3.4引入了对泛型函数更高阶类型推断的支持这是更高种类的类型的部分实现,但是没有可用的类型级语法。您可以将实际的通用函数转换为另一个通用函数,其中输出函数的类型与输入函数的类型完全相关。如果您没有实际的函数值,则可以制作一个或假装制作一个,对该值进行更高阶的推断,然后获取输出函数的类型。但是,正如您所指出的那样,如果您只关心键入,那么它将在您的输出中添加一些根本不需要的实际JavaScript。对于MyClass示例,它看起来像这样:

// abuse TS3.4 support for higher order inference from generic functions
const ctorArgs = <A extends any[], R>(f: new (...a: A) => R): (...a: A) => void => null!
const myFunc = ctorArgs(MyClass)
type MyFunctionType = typeof myFunc;

const myFunction: MyFunctionType = (...args) => {}
myFunction("click", ev => { ev.buttons })

您可以看到它ctorArgs正在执行所需的类型操作,但是在值级别。在上面的代码中,ctorArgs正在丢弃其输入而只是假装返回一个函数;反过来,我们将丢弃输出,只是获取其类型。

由于您无法逃脱JavaScript的这一部分,因此也许您可以实际使用它来发挥自己的优势并进行myFunction通用实现您将要执行的操作将需要一个构造函数并将其转换为返回void的函数?调用new它,然后丢弃结果?像这样:

const makeMyFunction = <A extends any[], R>(
  f: new (...a: A) => R): (...a: A) => void =>
    (...a) => { new f(...a) } // whatever the implementation should do

const myFunction = makeMyFunction(MyClass);

在这种情况下,myFunction免费提供。但这是否适用取决于您的用例,我不知道。


操场上的代码链接

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何检查无参数构造函数的类型?

函数采用二进制文件/流/文件名并将其转换为可读文本格式的适当参数/返回类型是什么?

TypeScript类型化函数参数接受任何

如何防止构造函数在C ++中强制转换参数类型?

如何使Rust函数接受任何浮点类型作为参数

如何在函数内部传递参数并将其转换为某个数据类型?

如何创建仅接受类型构造函数子集的函数?

将带有可选模板类型参数的函数传递给类构造函数,并将其分配给方法

接受任何可索引数据类型作为参数的函数

创建Arraylist作为接受Kotlin中任何类型的函数的参数

如何在ReasonML中编写带有类型变量的函数以接受任何类型的参数?

如何添加具有不同参数的函数并将类型返回给向量?

C ++-17:将函数指针转换为具有不同参数指针类型的函数

为采用带有类型参数的方法的类型类定义构造函数?

函数调用,将其void *参数转换为任何其他类型

EnumConverter构造函数如何获取类型参数

类型转换函数的参数

C ++从函数返回多个类型引用并将其转换为我们需要的类型

如何在python中对任何类型的文件进行分块并将其转换为字符串

如何创建一个接受不同参数类型的通用函数

构造函数,它将任何类型的函数作为参数

如何让我的重载构造函数接受任何数字类型?

如何在 C++ 中定义接受不同参数类型的函数向量?

如何声明一个泛型函数,该函数返回一个具有相同参数但其参数返回类型不同的函数(反应钩子)

接受转换为相同类型的 N 个参数

一个函数,它接受一个扩展基类型的构造函数并返回相同的构造函数减去第一个参数

如何创建一个接受任何有符号或无符号整数并将其转换为 u8 的通用函数?

函数如何接受满足接口的任何类型?

创建一个函数来查找某种类型的货币并将其转换为 pandas