TypeScript 通过动态属性名(括号符号)分配了错误类型的值,在某些情况下未报告,

tquggr8v  于 6个月前  发布在  TypeScript
关注(0)|答案(4)|浏览(55)

Bug报告

🔎 搜索关键词

不确定哪些关键词适用于此问题。

🕗 版本与回归信息

这种行为在4.7、4.8和4.9.0-dev.20220920中出现。

⏯ Playground链接

查看此处

💻 代码

type Key = 'a' | 'b';
type Values = Record<Key, { value: number }>;
const x: Values = { a: { value: 1 }, b: { value: 2 } };
const key: Key = 'a' as Key; // <= HERE: Without "as Key" it detects the type error
const y: Values = { ...x, [key]: { value: 'oops' } }; // <= OOPS: Wrong type for `value`!

一个变体:

type Key = 'a' | 'b';
type Values = Record<Key, { value: number }>;
const data: Values = { a: { value: 1 }, b: { value: 2 } };
// No error reported, while it returns the wrong type.
const example = (key: Key): Values => ({ ...data, [key]: { value: 'oops' } });
example('a'); // => {"a": {value: "oops"}, "b": {value: 2}}

🙁 实际行为

尽管在代码示例中 key 被输入为 "a" | "b",但TypeScript并未检测到我们试图为 value 属性使用错误的类型。

🙂 预期行为

类型应该被推断为 {a: {value: string}} | {b: {value: string}},从而导致错误,但实际上任何值都被默默接受,这破坏了类型契约。

2ledvvac

2ledvvac2#

为了明确:问题在于错误类型的代码被默默接受,而不是正确的代码被拒绝。

jpfvwuh4

jpfvwuh43#

这里的问题是我们没有一个类型来表示对象字面量(或者说,没有生成组合爆炸性的方法)。
如果你写了一个类似这样的东西:

type AlphabetChar = "a" | "b" | "c" /*... the rest ... */| "z";

declare function getRandomChar(): AlphabetChar;
const k1 = getRandomChar(), k2 = getRandomChar(), k3 = getRandomChar(), k4 = getRandomChar();
const obj = { [k1]: 0, [k2]: 0, [k3]: 0, [k4]: 0 };

那么对于 obj 的唯一精确类型就是具有 26 ** 4 = 456976 成分的类型。
我们可以尝试计算一个带有可选成员的悲观类型 - { a?: number, b?: number, c?: number ... }。当只有两个可能的键值时,这可能会有点傻,但至少是正确的。

tyky79it

tyky79it4#

至少,应该有一个选项可以拒绝故意破坏输入约定的代码,并要求开发者添加某种注解以使其通过。

相关问题