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

时间:2020-03-28 08:34:11

标签: typescript

我有一个数组对象,其中每个数组都是一对[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[]
}

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

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
}

2 个答案:

答案 0 :(得分:0)

我建议这样做:

type Item<T> = [T, (val: T) => any]


const items = {
    first: ['a', val => val.length] as Item<string>,
    second: [[1, 2], val => val.push(3)] as Item<number[]>
}

在这种情况下,我使用了强制类型转换,因为您在同一对象中具有不同的类型,但是我认为您可以重新排列数据结构以避免强制类型转换。

请参见Playground Link

答案 1 :(得分: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)
}

注意:

对于index signature,所有属性值必须具有相同的类型。因此,您不能有效地使用泛型类型参数。

TS目前还缺乏类似correlated types的结构来表达,即属性键与其值 per 属性之间存在联系,而不是所有属性都存在。

要解决该问题,我们可以像往常一样显式键入所有属性(为简化起见,省略),也可以选择更广泛的Items基本类型,并分别使用Item类型和{{1} }如上所示的工厂功能。

您最好不要在这里使用type assertion,因为它的编译器检查比常规的赋值检查要宽松得多。例如itemthird wouldn't trigger an error具有类型断言。