【问题标题】:Array destructuring inside object对象内部的数组解构
【发布时间】:2017-08-13 02:41:12
【问题描述】:

创建一个简单的数组并在一个(空)对象中对其进行解构:

const foo: Array<number> = [1, 2, 3, 4];
const bar: Array<number> = {...foo};

这里的类型检查不应该失败吗? bar 在我看来不像一个数组。 编辑器完全没有抱怨并将bar 视为数组类型,即使我可以在运行时轻松检查它不是。

编辑

Reproducing it easily in the TypeScript playground.

【问题讨论】:

  • 您使用的是哪个版本的tsc? 2.1.4 抱怨类型不匹配。
  • @Saravana 现场。刚刚从命令行检查,我得到了错误。所以在这种情况下,问题来自编辑器(vscode)。
  • 虽然我可以在 TypeScript 操场上重现它,但请参阅上面的编辑。
  • 我猜在 2.1.4 和 2.2.1 之间有些东西坏了/改变了。更新到 2.2.1 后,我不再收到编译器错误。
  • 可能不同之处在于,在旧版本中,展开运算符尚未实现,因此出现错误。

标签: typescript ecmascript-6 destructuring


【解决方案1】:

这看起来像是一个已知问题,因为 {...foo} 解构被编译成 Object.assign({}, foo),而 Object.assign() 被声明为

assign<T, U>(target: T, source: U): T & U;

所以当第二个参数为数组时,结果与数组类型兼容。

希望better typing for Object.assign is implemented:

我即将获得传播类型的 PR,所以当它们出现时, Object.assign 将更改为具有正确的类型:

分配(目标:T,源:U):{ ...T,...U }

如果实现正确,传播类型不应考虑不可枚举的属性,例如length,因此您的代码将给出与

相同的错误
const p: Array<number> = {};

// Type '{}' is not assignable to type 'number[]'.
// Property 'length' is missing in type '{}'.

【讨论】:

    【解决方案2】:

    让我们看看生成的javascript

    var __assign = (this && this.__assign) || Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    var foo = [1, 2, 3, 4];
    var bar = __assign({}, foo);
    

    因此,您基本上创建了一个与原始解构数组具有相同属性的对象 - 由于 typescript 是 structural typed,它会考虑与 Array 兼容的新对象,因为它是浅拷贝的。

    另一方面,如果你愿意:

    const foo1: Array<number> = [1, 2, 3, 4];
    const bar1: Array<number> = [...foo1];
    

    结果将是预期的数组的新实例。

    【讨论】:

    • 是的,我注意到 '[...foo1]' 有效,我试图理解为什么它在其他情况下没有抱怨。如果它会创建一个具有相同属性的对象,我希望在那里找到它们。例如,生成的对象没有长度属性,该属性存在于数组中。
    • 对我来说看起来像是一个错误而不是预期的行为。 {...foo} 显然是类数组而不是数组。不知道是不是已经被举报了。
    • 在我看来,这更像是一种权衡。一方面,我们在 typescript 中进行解构,只复制自己的可枚举属性,另一方面,我们在 javascript 中有像 Array 这样的对象,其中大多数属性和方法都是从原型继承的。所以我们有两个选择——要么从 lib.d.ts 中的 Array 定义中删除几乎所有的方法和道具——这样 typescript 就会知道要复制什么,或者保持原样——但会产生你观察到的副作用。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-05
    • 2023-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-09
    相关资源
    最近更新 更多