typescript - 当某些参数是通用的或匿名的时键入 compose
问题描述
我想要一个compose
实现函数组合的函数。我希望 of 的定义compose
是类型安全的,允许尽可能多的参数,并处理本身是通用或匿名的参数以正确输入。最后一个要求对我来说是一个绊脚石。
我当前的定义,使用Typescript 4.1 Release Candidate 中的递归条件类型:
type Compose<Fns extends any[]> =
Fns extends [(...args: infer Args) => infer Return] ? (...args: Args) => Return :
Fns extends [(...args: infer Args0) => infer Ret0, (arg: infer Arg1) => Ret1, ...infer Rest] ? (
[Ret0, Arg1] extends [Arg1, Ret0] ? Compose<[(...args: Args0) => Ret1, ...Rest]> :
never
) :
never;
declare function compose<Fns extends ((...args: any[]) => any)[]>(
...fns: Fns
): Compose<Fns>;
当所有函数都有固定的、定义的类型时,这非常有效:
declare function foo(x1: string, x2: number): number;
declare function bar(y: number): boolean;
declare function baz(z: boolean): string;
const foobarbaz = compose(foo, bar, baz); // (x1: string, x2: number) => string
当传递给的函数之一compose
是通用的时,问题就出现了:
declare function foo(x: string): number;
declare function bar<T>(foo: T): string;
const foobar = compose(foo, bar); // typed as `never`
在这里,foobar
是never
因为[Arg1, Ret0] extends [Ret0, Arg1]
签入Compose
失败。该检查失败,因为bar
' 的T
参数,因此Arg1
,被推断为unknown
,并且[unknown, number]
确实没有扩展[number, unknown]
。但当然,T
(and Arg1
)可能是 number
,在这种情况下[number, number] extends [number, number]
会通过。在很多情况下,Typescript 会自动推断出这样的泛型参数,但这里不会。
使用匿名函数可以看到同样的问题:
declare function foo(x: string): number;
const foobar = compose(foo, x => x.toLocaleString()); // typed as `(x: string) => any`
这里,x
是一个隐含的any
,而不是隐含number
的,如 的返回值所示foo
。
归根结底,这些问题并不令人惊讶:一个函数的返回值和下一个函数的参数的限制来自Compose
,直到返回值 on 才使用compose
。当 TS 开始处理这个问题时,参数和泛型参数已经被评估了。
我试图重新定义事物,以便在compose
函数必须相关的论点中有实际意义,而不仅仅是允许((...args: any[]) => any)[]
,但到目前为止还没有得到任何地方。打字稿继续只是推断any
或unknown
,整体打字只是中断。
作为参考,这是一次尝试:
type Composable<Types extends any[]> = Tail<Types> extends infer Tail ? Tail extends any[] ? {
[I in keyof Tail]: I extends keyof Types ? (arg: Types[I]) => Tail[I] : never;
} : never : never;
declare function compose<Fns extends Composable<T>, T extends any[]>(...fns: Fns): Compose<Fns>;
(Tail
是一种评估传递的数组类型的类型,没有它的第一个成员——在这里,Tail[I]
对应于系列中的下一项Types[I]
)
但这仅用于any[]
for T
,然后Composable<T>
最终与((arg: any) => any)[]
我之前的相同。所以没有任何帮助。
在不尝试使用条件类型的情况下,我们可以编写非可变版本来compose
解决这个问题(因为每个参数都是根据前一个参数定义的),但是它们只能处理一些硬编码的函数。这很可能是我将采用的解决方案,但我对这个问题的目标是避免这种情况。
解决方案
推荐阅读
- codeigniter - 最好在模型或控制器 Codeigniter 中编写一些算法
- android - 为什么改造从 ASP Web 服务获取数据太慢
- typescript - 如何使用泛型作为枚举的键
- python - python 3.9中的Tensorflow安装错误:无法安装tensorflow [WinError 2]
- c++ - MSVC:无效的 memcpy 优化?
- php - jquery刷新div内容(php函数不是文件)
- html - 链接区域大于图片
- c++ - C++刷新问题:为什么使用setvbuf后缓冲区之前的一些文本输出已满
- python - Python 中的 Apache Beam SQL 错误 - ValueError:不支持的类型:任何
- r - 在 dplyr 中重新编码以更改导致错误的标签:参数 2 必须命名,而不是未命名