如何从 Typescript 中固定对象的键创建映射类型
How do I create a mapped type from the keys of a fixed object in Typescript
我有一个这样的对象:
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<>
、转换等的组合,但无法弄清楚。有办法吗?
(我使用的是 Typescript 2.8.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)
多于。
我有一个这样的对象:
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<>
、转换等的组合,但无法弄清楚。有办法吗?
(我使用的是 Typescript 2.8.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)
多于。