Bug报告
我在进行“Type | Treat”的第五天时遇到了这个奇怪的行为。
🔎 搜索词
Map函数参数推断
🕗 版本与回归信息
- 这种行为在每个我尝试的版本中都存在,我也查看了关于类型系统行为的常见问题解答。
我尝试了所有带有 as
支持的 Playground 版本。
⏯ Playground 链接
带有相关代码的 Playground 链接
💻 代码
function bug<Es extends 'foo' | 'bar'>(_: { [E in Es as `on${E}`]: (e: string) => void }) {
}
bug({
onfoo(_e) {}, // _e: any; onfoo: (e: string) => void
onbar(_e) {} // _e: any; onbar: (e: string) => void
})
function workaround_1<Es extends 'foo' | 'bar'>(_: { [E in `on${Es}`]: (e: string) => void }) {
}
workaround_1({
onfoo(_e) {}, // _e: string
onbar(_e) {} // _e: string
})
function workaround_2<Es extends 'foo' | 'bar'>(_: Es extends never ? {} : { [E in Es as `on${E}`]: (e: string) => void }) {
}
workaround_2({
onfoo(_e) {}, // _e: string
onbar(_e) {} // _e: string
})
🙁 实际行为
onfoo
和 onbar
的类型被正确地推断为 (e: string) => void
,但参数 _e
被错误地类型化为 any
而不是 string
。
🙂 预期行为
我希望 _e
具有 string
的类型,因为已知该函数具有 (e: string) => void
的类型。我提供了两个类型正确的变体--一个没有使用 as
,另一个强制类型取决于 Es
。这三个都应该等效。我特别惊讶的是 bug
和 workaround_2
的行为不同,因为它只是强制将 Es
稍微提前评估。
3条答案
按热度按时间xcitsw881#
workaround_2
看起来很奇怪👀dfuffjeb2#
我们目前只实现了对Map类型的推理,没有
as
子句。在这些示例中,我们实际上并没有为Es
推断出任何内容,而是简单地默认为约束'foo' | 'bar'
,这恰好与提供的参数匹配。因此,这里隐含着对新功能的请求。话虽如此,似乎我们应该在调用
bug
的每个方法中对_e
进行上下文类型检查。我们可以看看如何解决这个问题,但如果没有实际支持带有as
子句的Map类型推理,那么帮助将不大。p1tboqfb3#
这很有道理。正如你所说,当从每个参数中移除
onbar
时,由于约束默认值的原因,bug
和workaround_1
调用被拒绝。不过我看到workaround_2
还是被接受了。(Playground)这个例子并不是来自任何实际的代码,所以如果它变得过于晦涩难懂而没有价值的话,我也不会有怨言。😃