如何从 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 接口?

Typescript 对象:如何将键限制为特定字符串?

创建一个具有可变长度数组的接口,其中包含 TypeScript/Angular4 中的对象

在 TypeScript 中迭代对象的键和值

Typescript:环境变量的类型 Guard 作为 JSON 对象的键