如何从Typescript中的固定对象的键创建映射类型

maj*_*oat 4 types typescript mapped-types

我有一个这样的对象:

const routes = {
  home: { path: '/', page: 'home' },
  profile: { path: '/profile', page: 'users/profile' }
}
Run Code Online (Sandbox Code Playgroud)

我想从中定义派生类型,如下所示:

type RouteName = keyof typeof routes,它会创建类似的类型"home" | "profile"

但是,我不能这样做:

for (let name in routes) {
  router.add({ name, ...routes[name]})
}
Run Code Online (Sandbox Code Playgroud)

因为编译器抱怨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.
Run Code Online (Sandbox Code Playgroud)

如果我将路由的定义修改为:

interface RouteDefinition {
  path: string
  page: string
}
const routes: {[key: string]: RouteDefinition} = {
  home: { path: '/', page: 'home' },
  profile: { path: '/profile', page: 'users/profile' }
}
Run Code Online (Sandbox Code Playgroud)

所生成的类型type RouteName = keyof typeof routes现在是string代替"home"|"profile"

我当然可以定义一个硬编码RouteName类型,但是如果不清楚,我将尽量避免在两个地方定义路由名称,特别是当对象的键严格定义可能性集时。

该对象仅需定义一次,而无需重新分配。我试过一堆的Readonly<>,转换等组合,但无法弄清楚。有没有办法做到这一点?

(我正在使用打字稿2.8.1)

Aar*_*all 6

TypeScript认为for..in键是类型中定义的键是不安全的,因为在JavaScript中所有对象都是打开的。

您可以使用断言来消除编译错误:

for (let name in routes) {
  routes[name as RouteName]; // no error
}
Run Code Online (Sandbox Code Playgroud)

或者,我要做的是结合两种方法。您可以在映射时定义自己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
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您的routes文字不满足RouteDefinition(缺少键,类型错误的键),那么您将在分配站点(即mapRoutes(routes)上方)收到错误消息。