基于第一项数组的值的数组第二项的打字稿值

Mic*_*hal 5 typescript

我有数组对象,其中每个数组都是pair [value, function],其中function接受value参数:

const items = {
    first: ['a', val => val.length], // val should be string
    second: [[1, 2], val => val.push(3)] // val should be number[]
}
Run Code Online (Sandbox Code Playgroud)

有没有办法将函数参数(第二个数组项)的类型设置为与第一个数组项的类型相同?我创建了这个,但它不起作用(函数参数的类型始终未知):

type Items = {
    [key: string]: any extends [infer Value, any] ? [Value, (val: Value) => any] : never
}

const items: Items = {
    first: ['a', val => val.length], // val should be string, but is unknown
    second: [[1, 2], val => val.push(3)] // val should by number[], but is unknown
}
Run Code Online (Sandbox Code Playgroud)

bel*_*a53 0

这是比hinosxz的答案( Playground )更安全的替代方案:

type Items = {
    [K: string]: Item<any, unknown>
}
type Item<T, U> = [T, (t: T) => U]

const item = <T, U>(...args: Item<T, U>) => args // factory fn

const items: Items = {
    first: item('a', val => val.length), // works
    second: item([1, 2], val => val.push(3)), // works

    third: item({}, val => val.length), // error (good)
    fourth: item({ 0: 1 }, val => val.push(3)) // error (good)
}
Run Code Online (Sandbox Code Playgroud)

笔记:

对于索引签名,所有属性值必须具有相同的类型。因此您无法有效地使用泛型类型参数。

此外,TS 目前缺乏类似相关类型的构造来表达,即属性键与其每个属性的值之间存在关系,而不是所有属性在一起。

为了解决这个问题,我们可以像往常一样显式输入所有属性(为简单起见而省略),或者选择更广泛的Items基本类型并使用Item类型和item工厂函数单独检查所有属性,如上所示。

您最好不要在这里使用类型断言,因为它的编译器检查比常规赋值检查更宽松。例如third,不会触发类型断言的fourth 错误。