从只读<数组>派生类型<MyType>无法按预期工作



TLDR;从数组派生类型没有按预期工作(Stacklitz对此进行了说明)。

为了改进代码库的某些部分,我偶然发现了几个不同的数组,这些数组用于将后台的信息映射到人类可读的字符串中,如下所示:

export const MyMapping = [
{ dbLabel: 'something', screenLabel: 'Something User-friendly' },
...
];

由于这在几个地方都存在;合同;的数组没有被某种类型强制执行,我继续写道:

export type DbLabelMapper = Record<'dbLabel' | 'screenLabel', string>;

(实际上第一个版本使用了一个接口,但想法是一样的)

然后,由于数据库标签在代码库的其他部分被用作类型,但被错误地用作strings,我继续做了以下操作:

export const MyMapping: Array<DbLabelMapper> = [
{ dbLabel: 'something', screenLabel: 'Something User-friendly' },
...
] as const;
export type MyMappingType = typeof MyMapping[number]['dbLabel'];

Typescript对我大喊大叫,因为我不应该将只读类型([...] as const)分配给可变类型(Array<DbLabelMapper>)。因此,我对映射签名进行了如下更正:

export const MyMapping: Readonly<Array<DbLabelMapper>> = [
{ dbLabel: 'something', screenLabel: 'Something User-friendly' },
...
] as const;
export type MyMappingType = typeof MyMapping[number]['dbLabel'];

现在,在那之后,我的MyMappingType就没有任何类型了。根据我的例子,我想要的是MyMappingType = 'something' | 'anotherThing' | '...'。我是做错了什么,还是错过了什么?

您为MyMapping提供了Readonly<Array<DbLabelMapper>>的显式类型。使用typeof MyMapping将返回此确切类型。

要解决此问题,您必须删除类型注释,并让TypeScript推断类型。

export const MyMapping = [
{ dbLabel: 'something', screenLabel: 'Something User-friendly' },
] as const

但是您将失去以前的类型安全性,因为您现在可以为MyMapping分配任何值。

TypeScript 4.9将引入satisfies运算符来帮助解决这种情况。

export const MyMapping = [
{ dbLabel: 'something', screenLabel: 'Something User-friendly' },
] as const satisfies Readonly<Array<DbLabelMapper>>
export type MyMappingType = typeof MyMapping[number]['dbLabel'];
//          ^? type MyMappingType = "something"

游乐场

最新更新