对强类型元组实现递归类型推理

问题描述 投票:0回答:1

我有一个 MyType 类型,看起来像这样

type MyType<V> {
  value: V
}

我正在尝试实现一个函数,该函数接受各种 MyType 对象的元组,并返回值。

期望的行为:

const obj1 = {value:1}
const obj2 = {value: "hello"}
const obj3 = {value: new Date()}

const values = getValues(obj1, obj2, obj3)
// Need typescript to infer that values is of type [number, string, Date]

我的尝试(当我尝试在递归函数调用中返回空列表时出现错误):

type Infer<T> = T extends MyType<infer V> ? V : never;

type InferRecursive<T extends any[]> =
    T extends [] ?
    [] : T extends [infer U, ...infer URem] ?
    [Infer<U>, ...InferRecursive<URem>]
    : never;

function getValue<T extends MyType<any>>(obj: T): Infer<T> {
    return obj.value;
}

function getValues<T extends MyType<any>[]>(...objs: T): InferRecursive<T> {
    if (objs.length === 0) {
        // *ERROR HERE* --> [] cannot be assigned to InferRecursive<T>
        return [];
    }
    const [next, ...rest] = objs;
    return [
        getValue(next), ...getValues(...rest)
    ]
}

期望的行为:

const obj1 = {value:1}
const obj2 = {value: "hello"}
const obj3 = {value: new Date()}

const values = getValues(obj1, obj2, obj3)
// Need typescript to infer that values is of type [number, string, Date]

我的尝试(当我尝试在递归函数调用中返回空列表时出现错误):

type Infer<T> = T extends MyType<infer V> ? V : never;

type InferRecursive<T extends any[]> =
    T extends [] ?
    [] : T extends [infer U, ...infer URem] ?
    [Infer<U>, ...InferRecursive<URem>]
    : never;

function getValue<T extends MyType<any>>(obj: T): Infer<T> {
    return obj.value;
}

function getValues<T extends MyType<any>[]>(...objs: T): InferRecursive<T> {
    if (objs.length === 0) {
        // *ERROR HERE* --> [] cannot be assigned to InferRecursive<T>
        return [];
    }
    const [next, ...rest] = objs;
    return [
        getValue(next), ...getValues(...rest)
    ]
}
typescript
1个回答
0
投票

您遇到的 TypeScript 错误是因为 TypeScript 编译器无法使空数组 (

[]
) 的类型与预期返回类型
InferRecursive<T>
保持一致。由于函数中的
T
可以是
MyType<any>[]
的任何元组类型,因此当您指定
[]
时,TypeScript 不会自动推断它与
T
可能代表的每种可能的元组结构兼容。

解决此问题的一种方法是将空数组显式转换为适当的类型。这是

getValues
函数的修改版本,应该可以工作:

type MyType<V> = {
  value: V;
}

type Infer<T> = T extends MyType<infer V> ? V : never;

type InferRecursive<T extends any[]> = 
  T extends [] ? [] :
  T extends [infer U, ...infer URem] ? [Infer<U>, ...InferRecursive<URem>] : 
  never;

function getValue<T extends MyType<any>>(obj: T): Infer<T> {
    return obj.value;
}

function getValues<T extends MyType<any>[]>(...objs: T): InferRecursive<T> {
    if (objs.length === 0) {
        // Explicitly cast the empty array to the expected return type
        return [] as InferRecursive<T>;
    }
    const [next, ...rest] = objs;
    return [
        getValue(next),
        ...getValues(...rest)
    ] as InferRecursive<T>;
}

此函数显式地将空数组

[]
转换为
InferRecursive<T>
以确保类型安全性和兼容性,允许 TypeScript 推断具有不同结构
MyType<any>

的元组的正确类型
© www.soinside.com 2019 - 2024. All rights reserved.