为什么只有具有内联类型的函数才能检测到额外的字段?

Why do only Functions with inline typing detect extra fields?

我的印象是这些函数虽然以不同的方式编写,但具有完全相同的类型签名; 即

type Test = {
  a: number
}
type Fu = (a: number) => Test

var foo1: (a: number) => Test = a => ({ a }) // aka var foo1: Fu = a => ({ a })
var foo2 = (a: number): Test => ({ a })  

最近我发现其中一个允许传入额外的字段

var foo1: (a: number) => Test = a => ({ a, b:1}) // NO error!
var foo2 = (a: number): Test => ({ a, b:2 }) // 'b' does not exist 

这是为什么?这是 TS 的错误还是限制?

有时我无法输入内联函数(即泛型、覆盖、回调)是否有另一种定义它们的方法,以便它始终像 foo2 一样运行?

playground link

Typescript 确实会对对象字面量进行额外的 属性 检查,但仅当在指定其类型的上下文中使用对象字面量时。当对象文字出现在推断其类型的上下文中时,则没有指定的类型来检查它。

在表达式 (a: number): Test => ({a, b: 2}) 中,return 类型注释 : Test 指定了对象字面量应该是什么类型,因此 Typescript 会进行额外的 属性 检查。

在赋值var foo1: (a: number) => Test = a => ({a, b: 1})中,右边是一个函数,其类型被推断为(a: number) => {a: number, b: number},这是一个非常合理的函数类型。函数本身没有类型注释,因此对象字面量用于推断函数的 return 类型,而不是用于检查对象字面量的函数的 return 类型。然后就没有错误了,因为函数类型可以分配给 foo1 的类型(因为函数类型在它们的 return 类型中是协变的)。

我不确定合适的解决方法是什么,但无论如何这就是为什么会发生这种情况的解释。