如何在不将数组设为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
相关产品推荐
相关产品推荐

