如何针对具有嵌套索引的现有类型创建强类型的映射文字?

时间:2019-05-22 20:46:33

标签: typescript typescript-typings

我认为我可能会碰到带有Typescript的打开错误(https://github.com/microsoft/TypeScript/issues/21760),但是我正在有效地尝试找出如何从其他文字常量创建映射的文字类型。

从下面的lodash函数中考虑正确的索引键入结果。

const result = _.mapKeys(en,x => x.display);


export const en = {
    ACTIVE: {
        ordinal: 0,
        display: 'Active',
    },
    INACTIVE: {
        ordinal: 1,
        display: 'Inactive',
    },
} as const;

// how do i type this?
export const displayToEnum = {};

// actual runtime implementation code
for (const key in en) {
    displayToEnum[en[key].display] = en[key];
}


// What i've tried

type Displays = typeof en[keyof typeof en]['display']

type DisplayToEnum = { 
    // how do i do this dynamically - find the mapped item which fits the conditional constraint
    [P in Displays]: P extends typeof en['ACTIVE']['display'] ? typeof en['ACTIVE'] : typeof en['INACTIVE'];
}

export const displayToEnum: DisplayToEnum = {} as any;

for (const key in en) {
    displayToEnum[en[key].ordinal] = en[key];
}

// its hardcoded, but this resolves correctly to 0.
const value = displayToEnum['Active'].ordinal;

1 个答案:

答案 0 :(得分:1)

您可以使用Extract根据当前属性en过滤P的值

export const en = {
    ACTIVE: {
        ordinal: 0,
        display: 'Active',
    },
    INACTIVE: {
        ordinal: 1,
        display: 'Inactive',
    },
} as const;

type En = typeof en

type DisplayEnum = {
    [P in En[keyof En]['display']]: Extract<En[keyof En], { display: P }>
}

或者您可以使用类似UnionToIntersection的方式从联合中构建类型,其中每个成员包含一个与display相同名称的属性

type UnionToIntersection<U> = 
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never

type DisplayEnum2 = UnionToIntersection<{
    [P in keyof En]: Record<En[P]['display'], En[P]>
}[keyof En]>;