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

如何在不将数组设为readonly的前提下提取数组对象属性为联合类型

从可变数组提取对象属性的字符串字面量联合类型

假设我们有这样的路由数组:

const routes = [
  { path: '/' },
  { path: '/test' },
  { path: '/new' },
]

我们需要从中提取路径对应的联合类型:

type Path = '/' | '/test' | '/new'

但直接用typeof routes[number]['path']只能得到宽泛的string类型,达不到预期效果。

现有的两种可行方案都有明显缺点:

  • 给每个对象单独加as const:重复代码太多,写起来麻烦
    const routes = [
      { path: '/' } as const,
      { path: '/test' } as const,
      { path: '/new' } as const,
    ]
    
  • 给整个数组加as const:会把数组变成readonly,没法后续修改数组

无需将数组设为readonly的实现方式

可以借助泛型函数来捕获字面量类型,同时保留数组的可变性:

// 泛型函数用于推导字面量类型,同时允许数组可变
function createRoutes<T extends { path: string }[]>(routes: [...T]) {
  return routes;
}

// 创建可变数组,TypeScript会自动捕获path的字面量类型
const routes = createRoutes([
  { path: '/' },
  { path: '/test' },
  { path: '/new' },
]);

// 提取预期的联合类型
type Path = typeof routes[number]['path']; // 类型为 '/' | '/test' | '/new'

// 验证可变性:正常添加新元素,类型也会自动更新
routes.push({ path: '/about' });
type UpdatedPath = typeof routes[number]['path']; // 类型变为 '/' | '/test' | '/new' | '/about'

如果希望初始的联合类型固定,不受后续数组修改影响,可以调整泛型函数:

function createFixedRoutes<T extends { path: string }[]>(routes: [...T]) {
  return routes as T;
}

const fixedRoutes = createFixedRoutes([
  { path: '/' },
  { path: '/test' },
  { path: '/new' },
]);

type FixedPath = typeof fixedRoutes[number]['path']; // 始终是 '/' | '/test' | '/new'

fixedRoutes.push({ path: '/about' }); // 数组可以修改,但FixedPath类型保持不变

原理是利用[...T]剩余元组类型,让TypeScript尽可能推导出具体的字面量值,而不是降级为string。同时返回的数组保持可变状态,满足后续修改需求。

内容的提问来源于stack exchange,提问作者v-moe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 09:35:22