给定一个函数,它接收两个相同泛型类型的参数:
declare const fn: <T>(t1: T, t2: T) => any;
我正在尝试推断调用此函数时 TypeScript 的不同行为。
当两个参数都是不同的原语时:
fn(1, 'foo'); // Error due to different types
当两个参数都是不同的对象时:
fn({ foo: 1 }, { bar: 1 }) // No error and return type is union of different types
为什么这两种用法的行为不同?我希望他们都表现得一样。要么:
- 类型不同导致的错误
- 没有错误,返回类型是不同类型的联合
其次,如果传入的参数之一是变量(而不是内联对象字面量),TypeScript 的行为又会有所不同:
fn({ foo: 1 }, { bar: 1 }) // No error and return type is union of different types
const obj = { foo: 1 };
fn(obj, { bar: 1 }) // Error due to different types
同样,这两种用法怎么没有相同的行为?我希望这两种情况的行为相同。
最佳答案
此行为的引人注目的用例来自这样的示例,其中您有一些候选类型集,没有一个是其他类型的父类(super class)型,但预期的推断类型参数 ({ a?: number, b ?: number, c?: number
) 很明显:
declare const fn: <T>(t1: T, t2: T, t3: T) => any;
fn({ a: 0, b: 1 }, { b: 2, c: 3 }, { a: 4, c: 5 });
为什么当参数不是对象文字时这不会发生?
当你有一些 binding foo
和一些类型 T
时,TypeScript 不能*知道 指向的对象foo
具有完全 T
类型 - 它可能具有更多 T
中未声明的属性>,但最终通过子类型关系绑定(bind)到 foo
。这在实践中很常见。
因此,在 OP 的示例中,推断类型 { foo?: number, bar?: number }
是不合理的,因为 obj
可能指向到具有 string
类型的 bar
属性的对象。
*
您可以在 const
周围添加更多特殊情况,这些情况是使用未类型断言的对象文字初始化的,但这只会使事情更加不一致
关于TypeScript:具有相同泛型类型的多个参数的函数的混合行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56603747/