输入元组,以便功能链具有有效的参数和返回类型 [英] Type tuple so that function chain has valid parameter and return types
问题描述
我想为下面的这个元组/数组创建一个类型。
I'd like to create a type for this tuple / array below.
在有效的地方:
const funcs = [(a: string) => 1, (a: number) => 'A', (a: string) => 2]
这是无效的:
const funcs = [(a: string) => 1, (a: number) => 2, (a: string) => 3]
区别在于中间函数的返回类型从字符串更改为数字。
The difference being the return type for the middle function changed from string to number.
有可能吗?
type SubtractOne<T extends number> = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62][T];
type AddOne<T extends number> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62][T];
const funcs = [(a: string) => 1, (a: number) => 'A', (a: string) => 2]
type CheckFuncs<T extends any[]> = { [(K extends number) in keyof T]: T[AddOne<K>] }
type funcsType = typeof funcs
type funcsType2 = CheckFuncs<funcsType>
在研究期间,我遇到了一种使用映射进行索引的方法。是否可以使用它在K中添加或减去 AddOne
?那么我可以访问 T [K]
的 ReturnType
和 Parameter< T [k +1]> [0]
?
During my research I came across a way to index with a mapping. Is it possible to use this to add or subtract AddOne
to K? then I can access the ReturnType
of T[K]
and the Parameter<T[k+1]>[0]
?
推荐答案
在给定索引类型的情况下,索引到元组的下一个或上一个值K
是我对元组休息/传播。考虑 Tail< T>
,它采用一个元组类型 T
并返回一个删除了第一个元素的新元组类型:
Indexing into the next or previous value of a tuple given an index type K
is something I'd do with the support for tuple rest/spread. Consider Tail<T>
, which takes a tuple type T
and returns a new tuple type with the first element removed:
// Tail<[1,2,3]> is [2,3]
type Tail<T extends readonly any[]> =
((...a: T) => void) extends ((h: any, ...r: infer R) => void) ? R : never;
然后 T [K + 1]
可以表示为 Tail< T> [K]
。
这可能是您所提问题的答案,但我将继续介绍如何使用它:
That's probably the answer to your question as asked, but I'll continue a little to show how to use it:
这是我开始编写您的 CheckFuncs
类型的方式:
Here's how I might start writing your CheckFuncs
type:
type CheckFuncs<T extends readonly ((x: any) => any)[]> = { [K in keyof T]:
K extends keyof Tail<T> ? (
[T[K], Tail<T>[K]] extends [(x: infer A) => infer R, (x: infer S) => any] ? (
[R] extends [S] ? T[K] : (x: A) => S
) : never
) : T[K]
}
经过 T
并比较 T [ K]
与 Tail< T> [K]
,并转换 T [K]
变成一个可以正常工作的版本。然后这些(请注意,您需要 const
断言以保留元组类型):
That walks through T
and compares T[K]
with Tail<T>[K]
, and converts T[K]
into a version of itself that works. Then these (note that you need const
assertions for the tuple type to be preserved):
const pass = [(a: string) => 1, (a: number) => 'A', (a: string) => 2] as const
const fail = [(a: string) => 1, (a: number) => 3, (a: string) => 2] as const
产生以下内容:
type passType = CheckFuncs<typeof pass>
// readonly [(a: string) => number, (a: number) => string, (a: string) => number]
type failType = CheckFuncs<typeof fail>
// readonly [(a: string) => number, (x: number) => string, (a: string) => number]
您可以创建一个与 CheckFuncs $一起使用的函数c $ c>像这样:
And you can make a function that works with CheckFuncs
like this:
function useFuncs<T extends readonly ((x: any) => any)[]>(...t: CheckFuncs<T>) { }
useFuncs((a: string) => 1, (a: number) => 'A', (a: string) => 2); // okay
useFuncs((a: string) => 1, (a: number) => 3, (a: string) => 2); // error!
// ----------------------> ~~~~~~~~~~~~~~~~
// Argument of type '(a: number) => number' is not assignable to
// parameter of type '(x: number) => string'.
当然,您想要编写或使用 CheckFuncs $的确切方法
可能有所不同;这只是一个例子。希望能有所帮助;祝你好运!
Of course the exact way you want to write or use CheckFuncs
might be different; this is just an illustration. Hope that helps; good luck!
这篇关于输入元组,以便功能链具有有效的参数和返回类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!