'is not assignable to parameter of type' 对象字面量错误

'is not assignable to parameter of type' error with object literal

对象文字类型有问题。

interface OptionalFoo {
  foo?: number;
}

interface Bar {}

function foobarFn(foobar: OptionalFoo & Bar) {}

foobarFn({ bar: 1 }); // error

foobarFn({ bar: 1 } as { bar: number }); // ok

foobarFn({ bar: 1 } as { bar: 1 }); // ok!

具有推断类型的对象文字导致类型错误:

Argument of type '{ bar: number; }' is not assignable to parameter of type 'OptionalFoo & Bar'

但问题不在于推理本身:

const bar = { bar: 1 }; // inferred { bar: number; }
foobarFn(bar); // ok!?

扩展语法与 Object.assign 存在相同问题:

foobarFn({...{ bar: 1 }}); // error

foobarFn(Object.assign({}, { bar: 1 })); // ok!?

有没有一种方法可以在没有就地对象文字的情况下使用推断的对象文字类型(过度 属性 检查)来实现行为,例如使用 bar 变量或函数调用,如 Object.assign({ bar: 1 })?

澄清一下,这不仅仅是关于超额 属性 检查。当我们将一个对象文字直接分配给一个位置时,多余的 属性 检查开始发挥作用。在您的情况下,间接分配对象时会发生所有更令人惊讶的行为,这通常会在过度 属性 检查下被允许。

function foo(o: { bar: number }) { }
foo({ bar: 0, foo: "" }) // error direct assignment
foo({ bar:0, foo: ""} as { bar:0, foo: "" }) // ok indirect

令人惊讶的是,至少对我来说,另一个检查(弱类型检查)没有发现这个错误。在弱类型检查(如 here 所述)下,如果一个类型只有可选属性,并且我们尝试分配一个没有共同属性的类型,我们应该得到一个错误:

function foo(o: { bar?: number }) { }
foo({ foo: "" }) // error under excess properties:  Object literal may only specify known properties, and 'foo' does not exist in type
foo({ foo: ""} as { foo: "" }) // error under weak types: Type '{ foo: ""; }' has no properties in common with type '{ bar?: number; }'.

我认为这是弱类型检查中的一个漏洞(我犹豫说 bug,不确定它是否是设计使然)。弱类型是(根据这个PR):

  1. Object types with at least one property
  2. Where all properties are optional
  3. And that do not have a string index signature, number index signature, call signature or construct signature.

然而,在对交集进行弱类型检查的过程中,交集的所有类型都必须是弱类型,交集才能成为弱类型。来自编译器代码(添加注释):

function isWeakType(type: Type): boolean {
    if (type.flags & TypeFlags.Object) {
       // ....
    }
    if (type.flags & TypeFlags.Intersection) {
        /// All intersection members have to be weak
        return every((<IntersectionType>type).types, isWeakType); 
    }
    return false;
}

因为 interface Bar {} 不是弱类型(根据第一条规则,它没有属性),与它的任何交集都不是弱类型,也不会抛出任何弱类型检查错误。从交集中删除 Bar 将在您分配与目标没有任何共同点的对象的任何地方抛出错误。