Typescript: 关于支持Object.assign的任何路线图?

创建于 2015-06-09  ·  47评论  ·  资料来源: microsoft/TypeScript

在1.6或2.0中?

Question

最有用的评论

对不起,我不明白。 ES6支持Object.assign因此Babel将其转换为ES5目标的polyfill。 我很困惑为什么TypeScript不能像其他ES6功能那样做同样的事情。

所有47条评论

不确定你在找什么。 如果您指的是类型,则它已在lib.es6.d.ts中定义为

    /**
      * Copy the values of all of the enumerable own properties from one or more source objects to a 
      * target object. Returns the target object.
      * <strong i="6">@param</strong> target The target object to copy to.
      * <strong i="7">@param</strong> sources One or more source objects to copy properties from.
      */
    assign(target: any, ...sources: any[]): any;

我的意思是实现,TypeScript不包含pollyfills,您可以始终包含您的内容,例如Mozilla为此提供了

如果您要询问mixin模式的类型,这是我们在2.0路线图中一直存在的问题。

谢谢。 我的意思是在TypeScript中编写Object.assign(...)并转换为es3 / es5 / es6。 因此它在2.0的路线图上。

:+1:

@unional我可能误会了一些东西。 但我认为您的结论不正确。

ES6无论如何都支持Object.assign ,因此,如果您的目标是ES6,则应该能够以TypeScript编写它。

但是,如果您转换到es5及以下版本,则仍然需要一个polyfill,因为es5没有Object.assign

作为快速解决方法,请考虑以下polyfill并输入:

interface ObjectConstructor {
    assign(target: any, ...sources: any[]): any;
}

if (typeof Object.assign != 'function') {
  (function () {
    Object.assign = function (target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert undefined or null to object');
      }

      var output = Object(target);
      for (var index = 1; index < arguments.length; index++) {
        var source = arguments[index];
        if (source !== undefined && source !== null) {
          for (var nextKey in source) {
            if (source.hasOwnProperty(nextKey)) {
              output[nextKey] = source[nextKey];
            }
          }
        }
      }
      return output;
    };
  })();
}

感谢您解决此问题。 很久以前了。 :)是的,我现在知道它只需要为es5使用polyfill。

再次感谢!

当目标设置为es5时,我们会编译此polyfill吗? 我的意思是,由于将编译目标设置为es5,因此这应该能够在es5环境下工作。

当目标设置为es5时,我们将编译此polyfill吗

是的,作为ponyfill:rose::horse:

对不起,我不明白。 ES6支持Object.assign因此Babel将其转换为ES5目标的polyfill。 我很困惑为什么TypeScript不能像其他ES6功能那样做同样的事情。

@prashaantt TypeScript不提供任何使然。 如果要使用Object.assign或较新的标准添加的其他任何原语/方法,则应该:

  • 使用带有相应类型的polyfill库(例如core-js
  • 在添加功能时定位标准(例如"target": "es6"中的tsconfig.json

@ devoto13谢谢, core-js运作良好。

我只是有一个愚蠢的问题。 在npm installtypings install core-js我开始为多填充方法获取IntelliSense。 但是我仍然需要在使用它们的每个模块中实际导入这些方法,否则编译后的代码将不包含polyfills,对吗?

@prashaantt任何东西都需要core-js/shimObject.assign从那时起在全球范围内可用。 我建议将import 'core-js/shim';放在主模块/入口点的顶部。

谢谢@jesseschalken。 作为后续措施,不是整个shim导入都会使我的捆绑包膨胀吗? 还是tscts-loader足够聪明,只挑选我的代码中实际使用的东西?

@prashaantt这取决于您要定位的浏览器。 您已经知道您定位的浏览器不支持Object.assign ,谁知道还不支持? 如果需要最大范围的浏览器支持,则需要捆绑包中的整个垫片。

如果只需要Object.assign的polyfill,则可以import 'core-js/modules/es6.object.assign'; ,并在需要时添加更多东西(请参阅core-js中的shim.js以获得列表)文档)。 Webpack将遵循需求图,仅包含必要的模块。

如果您已经在使用Babel,建议您使用import 'babel-polyfill';而不是直接使用core-js。 它包括core-js/shim ,还包括Generators / async-await的regenerator-runtime

感谢您的提示,尽管我们现在应该随时获得完整的生成器支持-实际上是2.0的最后一个障碍

对不起,我不明白。 ES6支持Object.assign,因此Babel会将其转换为ES5目标的polyfill。 我很困惑为什么TypeScript不能像其他ES6功能那样做同样的事情。

@prashaantt,当您说Babel _transpiles_ Object.assign什么意思? 它只是一个功能。 您可以添加polyfill,ponyfill或自己编写,也可以在任何环境中使用它-ES 3、1、5.1、6等。

@aluanhaddad我对babel的理解是,如果您将es5指定为目标并使用Object.assign ,它将自动包含Object.assign polyfill,如果您不使用它,则不会。 如果打字稿做同样的事情会很好,因为它声称它是“ es2015的超集”,如果它不提供可转换为较旧目标的功能,那不是真的。 (我可能是错的)

@ devoto13,如果您的目标是es5,则至少应发出警告,指出es5不支持Object.assign。 使其完全有效并且不告诉程序员您需要一些随机的polyfill是零意义。

@kyleholzinger您所描述的(针对ES5意味着Object.assign不可用)已经是该行为。

@kyleholzinger它确实会引发错误。 如果使用以下两个文件创建文件夹:

// test.ts
let t = Object.assign({}, {});
// tsconfig.json
{ "target": "es5" }

然后在其上运行tsc 。 您将收到以下错误:

$ tsc
test.ts(1,16): error TS2339: Property 'assign' does not exist on type 'ObjectConstructor'.

在您的项目中,您可能包括一些polyfill的类型输入,但不包括polyfill实现,这就是它失败的原因。

我了解这是目前的行为哈哈。 我的观点是,如果您将目标指定为es5,则打字稿会给您一个有意义的错误,而不是“它不在构造函数上”,那将是一个很好的选择。

@kyleholzinger FWIW,TypeScript 2.1现在支持ES6(ES7?)对象的剩余/扩展,因此我个人发现了较少的理由来烦扰Object.assign了。 使用本机生成器意味着我在大多数项目中不需要任何polyfill。

确实如此。 不遗漏语言功能真是太好了。 如果Object.assign不依赖于浏览器,并且如果您未使用polyfill,打字稿会警告您,那就太好了。

如果您的tsconfig设置正确,TypeScript会警告您有关assign无法用于<ES6的情况,方法是首先不给您选择在Object上自动完成该函数名称的选项。 如果您坚持不懈地手工编写,则会看到红色的花样。 如果您忽略该错误, tsc将给您以上错误。 但是,如果您也故意忽略了这一点,那么您理应受到的厄运。 ;)

是的,我唯一要说的是es2015规范,因此应该在打字稿中;)

定位es5如何在节点上使用Object.assign es5 ? 也就是说,代码将在服务器上而不是浏览器中运行。 我也使用填充胶吗?如何使用?

@johnbendi
它取决于节点的版本,也就是说,它取决于所有可填充功能的运行时。

这是测试运行时是否支持Object.assign

$ Node 
> Object.assign({ to: 'world' }, { message: 'Hello there!' })
{ to: 'world', message: 'Hello there!' }

如果上述方法奏效,您只需在tsconfig.json的"compilerOptions"."lib"属性中包含"es2017.object"

如果上述方法失败,则添加一个用TypeScript编写的polyfill。

// polyfill-object-assign.ts

if (typeof Object.assign !== 'function') {
  Object.assign = function (target, ...args) {

    if (!target) {
      throw TypeError('Cannot convert undefined or null to object');
    }
    for (const source of args) {
      if (source) {
        Object.keys(source).forEach(key => target[key] = source[key]);
      }
    }
    return target;
  };
}

并导入

import './polyfill-object-assign';

并且还对运行时支持的情况对tsconfig.json进行了相同的更改。

希望对您有所帮助

@aluanhaddad非常感谢您的见解。 根据您要求我运行的实验,我的节点确实支持Object.assign 。 但是即使添加了"compilerOptions": { "lib": ["es2017.object"] }我仍然得到squiggles 。 我应该忽略它还是有什么办法可以使它消失。

@aluanhaddad没关系。 现在效果很好。

@aluanhaddad我以前在获取squiggles时有"compilerOptions": { "lib": ["es2017.object", "es6"] } squiggles 。 删除es6似乎可以解决,但是再次重新运行gulp脚本会突然产生一组新的错误。
我的tsconfig.json:

{
    "compilerOptions": {
        "target": "es5",
        "module": "commonjs",
        "moduleResolution": "node",
        "lib": ["es2017.object"],
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "sourceMap": true,
        "inlineSources": true,
        //"noImplicitAny": true,
        "declaration": true,
        "noFallthroughCasesInSwitch": true,
        // "noImplicitReturns": true,
        "removeComments": true,
        "stripInternal": true,
        "outDir": "dist"
    },
    "files": ["src/main.ts"],
    "include": [
        "src/**/*.ts"
    ],
    "exclude": [
        "node_modules"
    ]
}

我的新错误示例:

error TS2318: Cannot find global type 'Array'.
error TS2318: Cannot find global type 'Boolean'.
error TS2318: Cannot find global type 'Function'.
error TS2318: Cannot find global type 'IArguments'.
error TS2318: Cannot find global type 'Number'.
error TS2318: Cannot find global type 'RegExp'.
error TS2318: Cannot find global type 'String'.
error TS2339: Property 'bind' does not exist on type '(message?: any, ...optionalParams: {}) => void'.
error TS2339: Property 'bind' does not exist on type '(message?: any, ...optionalParams: {}) => void'.
error TS2322: Type '{}' is not assignable to type
error TS2304: Cannot find name 'Promise'.

因此,有没有一种方法可以使用您的推荐并仍然使打字稿正确编译?

@johnbendi是的,当然可以。

用途我只是在建议添加特定条目"es2017.object"因为您的请求具有特殊性。
我相信"lib": ["es6"]不再正确,应该是"lib": ["es2015"]
尝试"lib": ["es2015", es2017.object"]或仅"lib": ["es2017"]

我认为所缺少的是一种干净的方式来表达“我有一个es6 polyfill,而不是您的商务打字稿,只是假设我这样做” :)。

因为设置target: "es6"做到这一点,但是大概也可以使用非polyfillable es6功能生成代码。

显式地要求core-js实质上迫使您具有填充,因为TS会抱怨,所以您不能进行有垫片和无垫片构建。

tsconfig.json files中将node_modules/typescript/lib/lib.es6.d.tsfiles做到这一点,但是..看起来并不干净...(或者我错过了实现这一目标的明显方法吗?)

@himdel只需使用

{
  "compilerOptions": {
    "lib": [
      "es2015"
    ]
  }
}

它运行完美-我已经做了几个月了。

或您希望的任何子集:

{
  "compilerOptions": {
    "lib": [
      "es2015.core",
      "es2016.array.include"
    ]
  }
}

我仍然不知道该怎么做。 当我有target: "es5" tsc时,总是会将Object.assign转换成对polyfill的调用。 添加库对我完全没有任何改变。

在我的情况下,我希望将箭头功能转换为普通功能,但不修改Object.assignArray.includes类的静态调用。

tsc应该有一个标志来告诉它仅可转译语法功能,不能告诉它诸如静态方法ObjectArray等的polyfill功能。

当我有目标时:“ es5” tsc将始终将Object.assign转换为对polyfill的调用。

@danez TypeScript不会修改对Object.assign的调用。 听起来您可能正在通过Babel运行代码?

@RyanCavanaugh确实如此。 Babel不参与该过程。
它所做的基本上是在改变这一点:

var a = Object.assign({}, {});

进入这个

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 a = _assign({}, {});

@danez您可以发布实际的复制品吗? 编译器未发出该代码

我没有存储库,但这是tsconfig:

{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "module": "ES2015",
    "target": "es5",
    "outDir": "js/lib/es"
  },
  "include": [
    "js/**/*.ts",
  ],
  "exclude": [
    "**/__tests__/**/*.ts"
  ]
}

然后我简单地叫tsc

@danez恐怕您必须发布实际的抄录。

C:\Throwaway\oat>type a.ts
var a = Object.assign({}, {});

C:\Throwaway\oat>type tsconfig.json
{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "module": "ES2015",
    "target": "es5",
    "outDir": "js/lib/es"
  },
  "include": [
    "*.ts",
  ]
}
C:\Throwaway\oat>tsc
a.ts(1,16): error TS2339: Property 'assign' does not exist on type 'ObjectConstructor'.

C:\Throwaway\oat>type js\lib\es\a.js
var a = Object.assign({}, {});

可能相关: https :

@unional可以正常工作。 编译器具有用于提供语法支持的帮助程序,但它不能在全局变量上_ever_重写功能。 @danez不能通过TypeScript代码访问该帮助程序。

const foo = { foo: 'bar' };
const bar = { ...foo };

将发出:

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 = { foo: 'bar' };
var bar = __assign({}, foo);

我认为您无法提供一个示例,其中Object.assign()被重写为__assign ,它仅用于对象扩展语法支持。

@kitsonk是的,我正在使用对象传播,您是对的。 因此,如果将对象传播简单地转换为Object.assign

@danez是在您定位支持Object.assign() (例如,目标为es2015 +)时。

例如,这:

const foo = { foo: 'bar' };
const bar = { ...foo };

将输出:

const foo = { foo: 'bar' };
const bar = Object.assign({}, foo);

@kitsonk是的,我知道,但是我的目标是es5 _syntax_,所有ES2017 +全局变量都由core-js填充。 所以我指的是一种可以输出es5语法但假定所有内置函数都可用的模式。 类似于babel使用useBuiltins选项进行的操作: https :

通常,我们不会竭尽全力为“混合”运行时目标提供特殊支持,但还有其他可用选项。

您可以将__assign注入到全局范围(以及其他任何帮助器,例如__extends )并与--noEmitHelpers

是的,我知道,但是我的目标是es5 _syntax_

我觉得这是不填充诸如Object.assign类的功能的主要问题。 一定要采取另一种立场-使用价差不能用__assign代替它的用法,但是当您直接调用它时却不能,这令人困惑

您不能在使用价差时用__assign代替它的用法,但在直接调用时不能用__assign代替,这令人困惑

我可以理解,您会感到困惑,但是如果您坚持这句话,TypeScript会提供_syntatical rewrites_而非_functional polyfills_。 TypeScript在行为方式上是完全一致的,并且对它的作用持肯定态度,并且99%的时间对最终用户没有影响。

正如@RyanCavanaugh所说,可以利用一组polyfills,再加上tslib ,再加上--noEmitHelpers加上一个表示以下内容的全局脚本:

__assign = Object.assign;

但这确实是“优胜劣汰”的TypeScript,并且可以说它将提供任何在现实世界中可衡量的性能改进。

此页面是否有帮助?
0 / 5 - 0 等级