代码之家  ›  专栏  ›  技术社区  ›  Estus Flask

“不可分配给”类型的参数,对象文本有错误

  •  1
  • Estus Flask  · 技术社区  · 6 年前

    对象文本类型有问题。

    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:number;”类型的参数不能分配给“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 回复  |  直到 6 年前
        1
  •  1
  •   Titian Cernicova-Dragomir    6 年前

    只是为了让事情清楚,这不仅仅是关于超额的财产检查。当我们将一个对象文字直接分配给一个位置时,多余的属性检查就会起作用。在您的情况下,当间接分配一个对象时,所有更令人惊讶的行为都会发生,这通常在过量的属性检查下是允许的。

    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. 并且没有字符串索引签名、数字索引签名、调用签名或构造签名。

    然而,在实施弱型交叉口检查时,所有类型的交叉口都必须是弱型交叉口才能成为弱型交叉口。来自编译器代码(添加了注释):

    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 在交集中,如果指定的对象与目标没有任何共同点,则会在任何地方引发错误。