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

TypeScript中DataAddress类型额外分支的成因及修复方案

TypeScript类型分支疑问与修正

代码示例

/* eslint-disable */
type Primitive = boolean | null | number | string;

export type DataAddress<T> = T extends Primitive ? [T] : ObjectAddress<T>;

export type ObjectAddress<T> = {
  [K in keyof T]: [K, ...DataAddress<T[K]>];
}[keyof T];

type X = { x: boolean[] }

function f(...args: DataAddress<X>) {

}


f('x1') 
/* TS2345: Argument of type ["x1"] is not assignable to parameter of type
 ["x", ...any[]] | ["x", number, false] | ["x", number, true]
 */

问题

类型中的["x", ...any[]]分支来自何处?如何修改代码,使该类型仅为["x", number, false] | ["x", number, true]?


一、["x", ...any[]]分支的来源

问题出在数组类型的处理逻辑上:

  1. boolean[]不属于Primitive定义的原始类型,所以会进入ObjectAddress<T>的处理流程。
  2. 在TypeScript中,数组本质是带number索引签名的对象,当用[K in keyof T]遍历数组的键时,TypeScript会保留数组的宽泛索引签名兼容性——这会导致DataAddress<T[K]>被推断成...any[],最终生成["x", ...any[]]这个不符合预期的分支。

简单来说,就是数组的对象特性让泛型映射时产生了宽泛的类型分支。

二、修改方案

要精准生成目标类型,需要在DataAddress中单独处理数组类型,避免直接丢给ObjectAddress处理。修改后的代码如下:

/* eslint-disable */
type Primitive = boolean | null | number | string;

// 新增数组类型的专属处理逻辑
export type DataAddress<T> = 
  T extends Primitive ? [T] : 
  T extends Array<infer U> ? DataAddress<U> extends [infer V] ? [number, V] : never :
  ObjectAddress<T>;

export type ObjectAddress<T> = {
  [K in keyof T]: [K, ...DataAddress<T[K]>];
}[keyof T];

type X = { x: boolean[] }

function f(...args: DataAddress<X>) {

}

// 此时DataAddress<X>的类型为["x", number, false] | ["x", number, true]
f('x1') 

修改说明

  • 新增数组判断逻辑:通过T extends Array<infer U>提取数组的元素类型U(此处为boolean)。
  • 对数组元素的类型递归处理:因为boolean是原始类型,DataAddress<U>会得到[false] | [true],再映射成[number, false] | [number, true]。
  • 最后代入ObjectAddress<X>后,就会生成精准的["x", number, false] | ["x", number, true],完全符合需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 21:05:12