TypeScript 参数类型在具有as的Map类型的值中未推断,

uelo1irk  于 22天前  发布在  TypeScript
关注(0)|答案(3)|浏览(15)

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
})

🙁 实际行为

onfooonbar 的类型被正确地推断为 (e: string) => void,但参数 _e 被错误地类型化为 any 而不是 string

🙂 预期行为

我希望 _e 具有 string 的类型,因为已知该函数具有 (e: string) => void 的类型。我提供了两个类型正确的变体--一个没有使用 as,另一个强制类型取决于 Es。这三个都应该等效。我特别惊讶的是 bugworkaround_2 的行为不同,因为它只是强制将 Es 稍微提前评估。

xcitsw88

xcitsw881#

workaround_2 看起来很奇怪👀

dfuffjeb

dfuffjeb2#

我们目前只实现了对Map类型的推理,没有as子句。在这些示例中,我们实际上并没有为Es推断出任何内容,而是简单地默认为约束'foo' | 'bar',这恰好与提供的参数匹配。因此,这里隐含着对新功能的请求。

话虽如此,似乎我们应该在调用bug的每个方法中对_e进行上下文类型检查。我们可以看看如何解决这个问题,但如果没有实际支持带有as子句的Map类型推理,那么帮助将不大。

p1tboqfb

p1tboqfb3#

这很有道理。正如你所说,当从每个参数中移除 onbar 时,由于约束默认值的原因,bugworkaround_1 调用被拒绝。不过我看到 workaround_2 还是被接受了。(Playground)
这个例子并不是来自任何实际的代码,所以如果它变得过于晦涩难懂而没有价值的话,我也不会有怨言。😃

相关问题