使用 const 断言从对象生成所有键的联合类型
Generate union type of all keys from an object with const assertion
我有一个这样的对象 (demo in ts playground):
const sites = {
stack: {url: 'https://whosebug.com/'},
google: {url: 'https://www.google.com/'},
azure: {url: 'https://portal.azure.com/'}
} as const
我想做的是用所有使用过的键创建一个联合类型,我可以这样做:
type SiteNames = keyof typeof sites; // "stack" | "google" | "azure"
但是,我还想将类型安全添加到 sites
初始化中,其中所有对象值都属于特定类型,例如 (demo in ts playground):
interface ISiteDetails {
url: string;
}
const sites: Record<string, ISiteDetails> = {
Whosebug: {url: 'https://whosebug.com/'},
google: {url: 'https://www.google.com/'},
azure: {url: 'https://portal.azure.com/'}
} as const
这在创建 sites
时提供了一些类型检查,但也从最终类型中删除了 const assertion,因此现在 SiteNames 仅解析为字符串:
type SiteNames = keyof typeof sites; // string
问题:有什么办法可以两者兼得吗?创建 Record<any, ISiteDetails
时的强类型化以及将所有对象键提取到新联合类型的能力?
解决方法:不符合人体工程学,但我可以通过将站点重新分配给导出变量来添加最后一层类型检查,如下所示 (demo in ts playground):
const SitesTyped: Record<SiteNames, ISiteDetails> = sites;
这通常是通过身份函数完成的。这将允许您限制输入,同时仍然使用它们的特定类型,例如 (demo in ts playground):
function defineSites<T extends Record<string, ISiteDetails>>(template: T) {
return template;
}
const sites = defineSites({
Whosebug: {url: 'https://whosebug.com/'},
google: {url: 'https://www.google.com/'},
azure: {url: 'https://portal.azure.com/'}
})
我有时会导入一点单行。这是高阶身份。
export const HOI = <Constraint> () => <T extends Constraint> (definition: T) => definition;
export const defineSites = HOI<Record<string, ISiteDetails>>();
// use as normal
如果在 .tsx
文件中需要它,您可能希望将它写成一个函数
export function HOI<Constraint>() {
return () => <T extends Constraint> (definition: T) => definition;
}
我有一个这样的对象 (demo in ts playground):
const sites = {
stack: {url: 'https://whosebug.com/'},
google: {url: 'https://www.google.com/'},
azure: {url: 'https://portal.azure.com/'}
} as const
我想做的是用所有使用过的键创建一个联合类型,我可以这样做:
type SiteNames = keyof typeof sites; // "stack" | "google" | "azure"
但是,我还想将类型安全添加到 sites
初始化中,其中所有对象值都属于特定类型,例如 (demo in ts playground):
interface ISiteDetails {
url: string;
}
const sites: Record<string, ISiteDetails> = {
Whosebug: {url: 'https://whosebug.com/'},
google: {url: 'https://www.google.com/'},
azure: {url: 'https://portal.azure.com/'}
} as const
这在创建 sites
时提供了一些类型检查,但也从最终类型中删除了 const assertion,因此现在 SiteNames 仅解析为字符串:
type SiteNames = keyof typeof sites; // string
问题:有什么办法可以两者兼得吗?创建 Record<any, ISiteDetails
时的强类型化以及将所有对象键提取到新联合类型的能力?
解决方法:不符合人体工程学,但我可以通过将站点重新分配给导出变量来添加最后一层类型检查,如下所示 (demo in ts playground):
const SitesTyped: Record<SiteNames, ISiteDetails> = sites;
这通常是通过身份函数完成的。这将允许您限制输入,同时仍然使用它们的特定类型,例如 (demo in ts playground):
function defineSites<T extends Record<string, ISiteDetails>>(template: T) {
return template;
}
const sites = defineSites({
Whosebug: {url: 'https://whosebug.com/'},
google: {url: 'https://www.google.com/'},
azure: {url: 'https://portal.azure.com/'}
})
我有时会导入一点单行。这是高阶身份。
export const HOI = <Constraint> () => <T extends Constraint> (definition: T) => definition;
export const defineSites = HOI<Record<string, ISiteDetails>>();
// use as normal
如果在 .tsx
文件中需要它,您可能希望将它写成一个函数
export function HOI<Constraint>() {
return () => <T extends Constraint> (definition: T) => definition;
}