You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

泛型场景下元组过滤递归中断的问题排查与修复

TypeScript类型推导问题:从ColumnDefinition元组生成目标对象类型

需求说明

我需要从定义好的columns元组类型,自动推导得到WANTED对象类型,相关代码如下:

declare class ColumnDefinition<T, R extends boolean = false, N extends string = string> {
    typeValidator: (v: unknown) => v is T;
    required: R;
    name: N;
};

type columns = [
    ColumnDefinition<number, true, 'ID'>,
    ColumnDefinition<string, true, 'text'>,
    ColumnDefinition<boolean, false, 'bool'>,
    ColumnDefinition<bigint, false, 'bigint'>,
];

type WANTED = {
    ID: number;
    text: string;
    bool?: boolean | undefined;
    bigint?: bigint | undefined;
};

尝试的解决方案及问题

我尝试用递归元组过滤的方法实现,但递归部分出现类型异常,代码如下:

type FilterColumns<
    Required extends boolean,
    COLUMNS extends readonly ColumnDefinition<any, boolean, any>[],
> = COLUMNS extends readonly [infer L, ...infer Rest]
    ? L extends ColumnDefinition<any, Required>
        ? [L, ...FilterColumns<Required, Rest>]
        : FilterColumns<Required, Rest>
    : [];

上述代码中,FilterColumns<Required, Rest>里的Rest被推断为unknown[],无法赋值给readonly ColumnDefinition<any, boolean, any>[]。请问为何Rest会被推断为unknown[]?该如何修复?

原因分析

TypeScript在处理泛型元组的解构推断时,即使COLUMNS被约束为readonly ColumnDefinition<any, boolean, any>[],当你使用COLUMNS extends readonly [infer L, ...infer Rest]语法时,解构后的剩余部分Rest并没有被自动继承原约束——泛型约束仅作用于完整的元组类型,剩余部分会 fallback 到最宽泛的unknown[]类型。

修复方案

方案一:修复递归过滤类型

在推断Rest时显式添加类型约束,让TypeScript明确剩余部分的类型:

type FilterColumns<
    Required extends boolean,
    COLUMNS extends readonly ColumnDefinition<any, boolean, any>[]
> = COLUMNS extends readonly [infer L, ...infer Rest extends readonly ColumnDefinition<any, boolean, any>[]]
    ? L extends ColumnDefinition<any, Required>
        ? [L, ...FilterColumns<Required, Rest>]
        : FilterColumns<Required, Rest>
    : [];

方案二:直接生成目标对象类型(更高效)

其实不需要先过滤元组,可以直接通过映射类型一步生成WANTED类型,跳过中间过滤步骤:

type FromColumns<COLUMNS extends readonly ColumnDefinition<any, any, any>[]> = {
    [C in COLUMNS[number] as C['name']]: 
        C extends ColumnDefinition<infer T, true, any> 
            ? T 
            : T | undefined;
};

// 直接得到目标类型
type WANTED = FromColumns<columns>;

这个方案直接遍历元组中的每个ColumnDefinition,根据required字段决定属性是否可选,同时提取对应的类型T,完全满足需求。

内容的提问来源于stack exchange,提问作者Akxe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 15:42:34