我对变量"day"有一个类型断言,因此当我为键指定boolean时,它不会抛出任何错误.

我不是这样做的

请判断下面的示例,并建议需要更改哪些内容才能使其抛出错误?

    type Day = 0 | 1 | 2;

type TTime = {
    [K in Day]?: string
}

const day = 2 as Day;

const obj: TTime = {
    [day]: true // Expect this to throw error as 'boolean is not assignable to key
}

我试图解决的另一个详细例子.I have to get the keys of another object(which is by default string[]) and do type assertion

type Day = 0 | 1 | 2;

type TTime = {
    [K in Day]?: string
}

const result: TTime = {
    2: 'I am result'
}

const keys = Object.keys(result);

let obj: TTime;
keys.forEach((key) => {
    const k = key as unknown as Day;
    const value = result[k]; //Key is string, so needs to be type asserted
    obj = {
        [k]: true //k is 2 in this case, but the value is boolean type and incorrect, this error
                  // is thrown when I remove the type assertion added and hardcode k as 2.
    }
})

推荐答案

不幸的是,您遇到了两个类型脚本限制或错误...第一个是次要的,但它会导致主要的.


小问题是microsoft/TypeScript#13948,其中一个computed property keyunion type的对象被赋予了index signature,这不必要地将对象类型扩展到了不太有用的类型.例如:

const v = { [Math.random() < 0.5 ? "a" : "b"]: 123 };
// const v: { [x: string]: number;}

运行时,值v将为{a: 123}{b: 123}.因此,如果脚本的类型是{a: number} | {b: number},那么它应该是v.相反,它推断出{ [x: string]: number }...就编译器而言,它完全不知道v的密钥名是什么;只是它的所有属性都是number型.

就你而言,你有

const obj = { [day]: true };
// const obj: { [x: number]: boolean; }

obj已经从{0: boolean} | {1: boolean} | {2: boolean}扩大到{[x: number]: boolean},完全忘记了Day.

这个问题并不是灾难性的,因为实际的类型至少是compatible,而所需的类型是次优的.


第二个bug是microsoft/TypeScript#27144,其中带有索引签名的对象类型可分配给带有所有optional propertieseven if the property value types are incompatible的类型.这很糟糕:

const v: { [k: string]: number; } = {a: 1};
const x: { a?: string } = v; // no error!

v的类型有一个索引签名,其中所有属性都必须有number类型值.同时,如果x类型存在,则它具有string类型值的单个可选属性.这些不应该被认为是兼容的,但它们是兼容的.因此,在没有编译器警告的情况下,可以错误地将v分配给x.

就你而言,你有:

const p: TTime = o; // no error

其中,TTime类型具有所有可选属性,并且被认为与o的索引签名类型兼容,尽管booleanstring不兼容.

Yuck.


所以这两个问题的相互作用导致了你的问题.在这里,"正确"的做法可能是等待/游说microsoft/TypeScript#27144得到修复.如果你想讨论这个问题????, 不会痛的.这可能也帮不了什么忙.谁知道什么时候,甚至是否会得到解决.

与此同时,你必须处理好它.

一种方法是为microsoft/TypeScript#13948做一个变通方案.我们不必满足于索引签名类型,而是可以编写一个帮助函数,直接确定该值是更有用的类型.这样地:

const kv = <K extends PropertyKey, V>(
  k: K, v: V
) => ({ [k]: v }) as { [P in K]: { [Q in P]: V } }[K];

kv函数接受一个键和一个值,并生成一个对象,该对象具有与该键和值对应的一个属性:

const y = kv("a", 123);
// const y: { a: number; }

如果在键为联合类型时执行此操作,则会得到联合类型的输出:

const w = kv(Math.random() < 0.5 ? "a" : "b", 123);
// const w: {a: number} | {b: number}

所以你可以用它来制作obj:

const obj = kv(day, true);
// const obj: { 0: boolean; } | { 1: boolean; } | { 2: boolean; }

既然obj没有索引签名,我们就不会遇到microsoft/TypeScript#27144:

const obj: TTime = kv(day, true); // error,
// boolean is not assignable to string

编译器能够看到{0: boolean} | {1: boolean} | {2: boolean}TTime不兼容,因为booleanstring不兼容.

Playground link to code

Javascript相关问答推荐

按下同意按钮与 puppeteer 师

使搜索栏更改语言

屏幕右侧屏障上的产卵点""

Prisma具有至少一个值的多对多关系

Ember.js 5.4更新会话存储时如何更新组件变量

Use Location位置成员在HashRouter内为空

同一类的所有div';S的模式窗口

邮箱密码重置链接不适用于已部署的React应用程序

以编程方式聚焦的链接将被聚焦,但样式不适用

expo 联系人:如果联系人的状态被拒绝,则请求访问联系人的权限

Node.js API-queryAll()中的MarkLogic数据移动

在Java脚本中录制视频后看不到曲目

Reaction即使在重新呈现后也会在方法内部保留局部值

正则表达式以确定给定文本是否不只包含邮箱字符串

如果查询为空,则MongoDB将所有文档与$in匹配

我想为我的Reaction项目在画布上加载图像/视频,图像正在工作,但视频没有

:host::ng-Deep不将样式应用于material 复选框

如何在预览中显示html+css与数据URL?

try 导入material 时出现错误NG0203

在给定的最小值、最大值和分辨率下计算相同分布的值