首页 > 解决方案 > Typescript 中映射类型的索引签名

问题描述

type Scales = 'xxs' | 'xs' | 's' | 'm' | 'l' | 'xl' | 'xxl'
type TScale = { [k in Scales]: number }
type TSizing1 = { [k in Scales]?: string }
type TSizing2 = { [k in Scales]: string }

const scale: TScale = {
    xxs: 1 / 8,
    xs: 1 / 4,
    s: 1 / 2,
    m: 1,
    l: 2,
    xl: 4,
    xxl: 8,
}

const sizing1: TSizing1 = {}
Object.entries(scale).forEach(([key, value]: [string, number]) => {
    sizing1[key] = `${value * 1.6}rem`
})
const sizing2: TSizing2 = Object.assign(
    {},
    ...Object.keys(scale).map(k => ({ [k]: `${scale[k] * 1.6}rem` })),
)

sizing1 和 sizing2 都会出错,因为 TSizing1 和 TScale 分别缺少索引签名。但是我应该如何将索引签名添加到映射类型?

标签: typescript

解决方案


问题不在于如何定义TSizing1or ,而是在调用orTSizing2时如何处理对象类型。Object.prototype.entriesObject.prototype.keys

解决方案

告诉 TypeScript 在对对象进行操作时使用缩小的特定类型。替换这些:

Object.entries(scale)
Object.keys(scale)

和那些:

(Object.entries(scale) as [Scales, number][])
(Object.keys(scale) as Scales[])

所以解决方案看起来像:

(Object.entries(scale) as [Scales, number][]).forEach(([key, value]) => {
    sizing1[key] = `${value * 1.6}rem`;
});

const sizing2: TSizing2 = Object.assign(
    {},
    ...(Object.keys(scale) as Scales[]).map(k => ({ [k]: `${scale[k] * 1.6}rem` })),
);

解释

TypeScript 在推断对象类型时非常糟糕。即使我们确切地知道是什么键scale(它们的定义非常明确Scales),TypeScript 仍会将它们视为只是一些类型的数据string。信息丢失。

为了弥补这种损失,断言它们的类型是你所知道的。


推荐阅读