【问题标题】:Type tuple so that function chain has valid parameter and return types键入元组,使函数链具有有效的参数和返回类型
【发布时间】:2020-03-13 13:38:03
【问题描述】:

我想为下面的这个元组/数组创建一个类型。

这是有效的:

const funcs = [(a: string) => 1, (a: number) => 'A', (a: string) => 2]

这是无效的:

const funcs = [(a: string) => 1, (a: number) => 2, (a: string) => 3]

区别在于中间函数的返回类型从字符串变成了数字。

有可能吗?

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]ReturnTypeParameter&lt;T[k+1]&gt;[0]

Playground

【问题讨论】:

标签: arrays typescript tuples


【解决方案1】:

在给定索引类型K 的情况下对元组的下一个或上一个值进行索引是我对variadic tuple types 的支持所做的事情。考虑Tail&lt;T&gt;,它接受一个元组类型T 并返回一个删除了第一个元素的新元组类型:

// Tail<[1,2,3]> is [2,3]
type Tail<T extends readonly any[]> = T extends [any, ...infer R] ? R : never;

那么“T[K+1]”可以改为Tail&lt;T&gt;[K]

这可能是您所问问题的答案,但我将继续展示如何使用它:


我可能会这样开始写你的CheckFuncs 类型:

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&lt;T&gt;[K] 进行比较,然后将T[K] 转换为可以工作的自身版本。然后是这些(请注意,您需要const assertions 才能保留元组类型):

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 一起使用的函数:

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 的确切方式可能会有所不同;这只是一个例证。希望有帮助;祝你好运!

Link to code

【讨论】:

  • 请问为什么最后你返回的是(x: A) =&gt; S而不是never
  • 你可以在操场上自己测试;如果您这样做,则错误函数的错误消息是“(a: number) =&gt; number 类型的参数不可分配给never”,这并没有真正告诉您如何修复它。对比上面的错误信息“(a: number) =&gt; number is not assignable to (x: number) =&gt; string 所以你可以看到你需要将返回类型更改为string(好吧,或者下一个函数的参数为​​number,但是? ‍♂️)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-23
  • 2016-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多