【问题标题】:Generate union type of all keys from an object with const assertion使用 const 断言从对象生成所有键的联合类型
【发布时间】:2021-11-09 23:25:40
【问题描述】:

我有一个这样的对象 (demo in ts playground):

const sites = {
    stack: {url: 'https://stackoverflow.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> = {
    stackoverflow: {url: 'https://stackoverflow.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&lt;any, ISiteDetails 时的强类型化以及将所有对象键提取到新联合类型的能力?

解决方法:不符合人体工程学,但我可以通过将站点重新分配给这样的导出变量来添加最后一层类型检查 (demo in ts playground):

const SitesTyped: Record<SiteNames, ISiteDetails> = sites;

【问题讨论】:

    标签: typescript keyof


    【解决方案1】:

    这通常是通过一个标识函数来完成的。这将允许您限制输入,同时仍然使用它们的特定类型,例如 (demo in ts playground):

    function defineSites<T extends Record<string, ISiteDetails>>(template: T) {
        return template;
    }
    
    const sites = defineSites({
        stackoverflow: {url: 'https://stackoverflow.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;
    }
    

    【讨论】:

    • 您的 Playground 处于反应模式,@KyleMit,这意味着类型约束被解释为 jsx 标签。试试这样:
    • 如果您在实际代码中的 .tsx 文件中需要它,无论出于何种原因,您都可以将其定义为函数而不是 lambda 表达式。我已经用那个版本为你更新了我的答案。
    猜你喜欢
    • 2020-02-08
    • 1970-01-01
    • 2020-04-02
    • 2018-08-30
    • 2013-10-12
    • 1970-01-01
    • 1970-01-01
    • 2018-09-06
    • 1970-01-01
    相关资源
    最近更新 更多