如何从 Typescript 中的固定对象的键创建映射类型
Posted
技术标签:
【中文标题】如何从 Typescript 中的固定对象的键创建映射类型【英文标题】:How do I create a mapped type from the keys of a fixed object in Typescript 【发布时间】:2018-10-08 18:22:54 【问题描述】:我有一个这样的对象:
const routes =
home: path: '/', page: 'home' ,
profile: path: '/profile', page: 'users/profile'
我想从中定义一个派生类型,如下所示:
type RouteName = keyof typeof routes
,创建类似"home" | "profile"
的类型。
但是,我不能这样做:
for (let name in routes)
router.add( name, ...routes[name])
因为编译器抱怨 routes[name]
是隐式类型 any
:
Element implicitly has an 'any' type because type ' home: path: string; page: string; ; profile: path: string; page: string; ;' has no index signature.
如果我将路由的定义修改为:
interface RouteDefinition
path: string
page: string
const routes: [key: string]: RouteDefinition =
home: path: '/', page: 'home' ,
profile: path: '/profile', page: 'users/profile'
生成的类型type RouteName = keyof typeof routes
现在是string
而不是"home"|"profile"
。
我当然可以定义一个硬编码的RouteName
类型,但如果不清楚,我会尽量避免在两个地方定义路由名称,尤其是当对象的键严格定义一组可能性。
对象只需要定义一次,永远不需要重新分配。我尝试了Readonly<>
、casting 等的一系列组合,但无法弄清楚。有没有办法做到这一点?
(我使用的是 Typescript 2.8.1)
【问题讨论】:
使用for/in
时,推断类型有this issue。但看起来他们并不打算改变当前的行为。
【参考方案1】:
TypeScript 认为假设 for..in
键正是类型中定义的键是不安全的,因为在 javascript 中所有对象都是打开的。
您可以使用断言来消除编译错误:
for (let name in routes)
routes[name as RouteName]; // no error
或者,我要做的是将您的两种方法结合起来。您可以在执行过程中定义routes
,将键提取为RouteName
,但也可以创建RouteDefinition
并将您的路由分配给索引类型(这可以使用对新变量的断言来完成,或者一个函数参数)当你想映射它们时:
interface RouteDefinition
path: string;
page: string;
const routes =
home: path: '/', page: 'home' ,
profile: path: '/profile', page: 'users/profile'
type RouteName = keyof typeof routes;
mapRoutes(routes);
function mapRoutes(routes: [key: string]: RouteDefinition )
for (let name in routes)
routes[name] // no error
如果您的routes
文字不满足RouteDefinition
(缺少键,键类型错误),那么您将在分配站点收到错误,即上面的mapRoutes(routes)
。
【讨论】:
以上是关于如何从 Typescript 中的固定对象的键创建映射类型的主要内容,如果未能解决你的问题,请参考以下文章
如何根据从另一个可观察对象返回的数组中的键创建可观察/ http请求数组
如何创建具有索引签名和不同类型的固定属性的 TypeScript 接口?