Bug报告
🔎 搜索词
名义,记录,品牌
🕗 版本与回归信息
3.3.3 至 4.3.2
- 这是我在每个版本中尝试的行为,我查阅了关于名义类型和记录类型的FAQ条目
⏯ Playground链接
带有相关代码的Playground链接
💻 代码
type Id = string & { __id: 'id' }
type User = {
id: Id;
name: string;
}
type Users = Record<Id, User>;
type Users2 = Map<Id, User>;
type Users3 = Record<string, User>;
// This will not produce an error
// @ts-expect-error No name should be an error!
const users: Users = { id0: { id: 'id', } }
// type: [string, unknown][]
const entries = Object.entries(users);
const users2: Users2 = new Map();
// @ts-expect-error No name produces an error
users2.set('id' as Id, { id: 'id' as Id, })
// @ts-expect-error No name produces an error
const users3: Users3 = { id0: { id: 'id' as Id, } }
// type: [string, User][]
const entries3 = Object.entries(users3);
🙁 实际行为
使用名义/品牌类型作为记录类型的键会导致 value
类型的类型检查被跳过。此外,推理也会失败并回退到 unknown
,例如使用 Object.entries
。使用 Map
可以按预期工作,但不能使用 Record
。我知道 Map(真实)和 Record(类型)之间的运行时行为完全不同,我只是提供一个例子。
🙂 预期行为
我希望在使用名义/品牌类型作为记录类型的键时,类型能够得到保留和检查。
5条答案
按热度按时间2izufjch1#
在这里的行为并不明显;如果你写了
,这似乎不符合对象契约,因为
"foo"
不是一个Id
,但你实际上无法构造那种对象。字符串对象的交集已经有点滥用了,可以认为当前行为是正确的。我怀疑改变这种行为会是一个破坏性的变化。
nfeuvbwi2#
感谢您的解释!这确实有道理。
不过我担心的是,在您的示例中,
SomeUser
可以是任何东西,TS 无法捕获它:TS 至少不应该反对
Users
类型上没有string: boolean
索引签名吗?niwlg2el3#
我注意到在我检查的每个编译器版本中,品牌字符串键记录都被错误地分配给了彼此:
Playground Link
我认为这是这里讨论的相同问题,但我不确定。这也可能是一个 #15746 或一些新的东西。
几年前,我注意到对品牌字符串键的支持得到了改进(尽管我不记得是哪个版本了,而且路线图也没有激发我的记忆),所以我发现这个漏洞令人惊讶。
nfzehxib4#
@RyanCavanaugh,虽然这是真的,但这仍然是
string & { __id?: 'id' }
的问题-几乎所有的string
都可以分配给。wnvonmuf5#
另一个同样问题的变体在这里展示: