“无法分配给类型的参数”对象文字错误

时间:2018-11-23 10:30:18

标签: typescript type-inference

对象文字类型有问题。

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!

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

  

'{bar类型:数字的参数; }”不能分配给“ 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 })

1 个答案:

答案 0 :(得分: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. 具有至少一个属性的对象类型
  2.   
  3. 所有属性都是可选的
  4.   
  5. 并且没有字符串索引签名,数字索引签名,调用签名或构造签名。
  6.   

但是,在对路口进行弱类型检查时,所有相交类型都必须为弱类型,以使路口成为弱类型。从编译器代码(添加注释):

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会在您分配与目标没有任何共同之处的任何地方抛出错误。