146

I am using TypeScript in my application, where I use function:

Object.assign(this.success, success.json())

However, during compilation, I receive the following error:

 error TS2339: Property 'assign' does not exist on type 'ObjectConstructor'.

Do you have any idea how can I get rid of this error?

uksz
  • 18,239
  • 30
  • 94
  • 161

8 Answers8

199

Configure:

If you're using VS code (or if you see a tsconfig.json file):

You should add the lib property to your tsconfig.json and then your editor will use the bundled typescript type definitions and also give you intellisense.

Just add the "lib": ["esnext", "dom"] to your tsconfig.json and restart VS Code

{
    "compilerOptions": {
        // ...
        "target": "es5",
        "lib": ["esnext", "dom"]
        // ...
    }
}

See all tsconfig.json options here.

If you're using Visual Studio or MSBuild include this tag:

<TypeScriptLib>esnext, dom</TypeScriptLib>

See all MSBuild typescript compiler options and usage here.


Check your work:

If you've configured your project to use the built-in types and restarted your editor, then your resulting type will look like this instead of the type being any when you use Object.assign:

code example 1


Note on polyfills and older browser compatibility:

Note that if you are transpiling to ES5 or lower and are targeting IE11, you will need to include polyfills because the typescript compiler will not include the polyfills for you.

If you'd like to include the polyfills (which you should) then I would recommend using core-js's polyfills.

npm install --save core-js

or

yarn add core-js

Then in the entry point in your app (e.g. /src/index.ts) add the import for core-js at the top of the file:

import 'core-js';

If you're not using a package manager then you can just paste the following polyfill taken from MDN in some place in your code that runs before the your usage of Object.assign.

if (typeof Object.assign != 'function') {
  // Must be writable: true, enumerable: false, configurable: true
  Object.defineProperty(Object, "assign", {
    value: function assign(target, varArgs) { // .length of function is 2
      'use strict';
      if (target == null) { // TypeError if undefined or null
        throw new TypeError('Cannot convert undefined or null to object');
      }

      var to = Object(target);

      for (var index = 1; index < arguments.length; index++) {
        var nextSource = arguments[index];

        if (nextSource != null) { // Skip over if undefined or null
          for (var nextKey in nextSource) {
            // Avoid bugs when hasOwnProperty is shadowed
            if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
              to[nextKey] = nextSource[nextKey];
            }
          }
        }
      }
      return to;
    },
    writable: true,
    configurable: true
  });
}
Rico Kahler
  • 17,616
  • 11
  • 59
  • 85
  • 4
    I tried "lib":["es2015","es2017","dom"] but I still get **Property 'values' does not exist on type 'ObjectConstructor'.**, I guess its not in the spec – Nikos Apr 14 '17 at 11:16
  • 1
    @Nikos did you restart vs code? [`Object.values` is in the spec.](https://tc39.github.io/ecma262/2017/#sec-object.values) and [typescript has typings for it](https://github.com/Microsoft/TypeScript/blob/v2.2.2/lib/lib.es2017.object.d.ts). – Rico Kahler Apr 14 '17 at 13:54
  • If by any chance WebStorm gives you an error, you need to install the Javascript.next plugin here : https://plugins.jetbrains.com/plugin/7643-javascript-next-support-plugin –  Oct 11 '17 at 19:18
  • Modifying tsconfig.json is the only workaround that works for me. i.e adding ```"lib": [ "es2015", "es2017", "dom" ] ``` – Danny Sofftie Mar 28 '18 at 12:55
  • Great, except Visual Studio fix not quite right. Need ES2015 in project properties or set target in Typescript build properties in project – AQuirky Sep 08 '18 at 16:01
  • 2
    @AQuirky The `TypeScriptTarget` option changes the target version of EmcaScript (~the formal javascript name). FYI: `ES2015` is not compatible for IE11 (in case you have to support it). You can still set `TypeScriptTarget` to `ES5` while also setting `TypeScriptLib` to `DOM, ES2015` to achieve the same fix while also remaining compatible with IE11 (but if you don't have to support IE, then just set `TypeScriptTarget ` to `ES2015`). – Rico Kahler Sep 08 '18 at 16:21
  • I've tried every solution on this reply, the one below, a similar one on Stack Exchange. The only thing I haven't tried is the (Object) because I can't change the original source. None of these work. Has something changed since these were first posted? – aphenine Mar 12 '19 at 16:07
  • i am gettign error in object.entries() while writing unit tests in angular 4. error message is 'undefined is not a constructor' (evaluating Object.entries()) – Irrfan23 Jun 17 '19 at 06:54
  • FYI: If you DON'T have a Tsconfig file and only the CLI, then you can do this : [ tsc --lib 'es2015','es2017','dom' foo.ts ] which has the same effect as specifing those 3 libs in tsconfig. – shawty Mar 06 '20 at 17:00
147

You can use type assertion, like this:

(<any>Object).assign(this.success, success.json())
Amid
  • 21,508
  • 5
  • 57
  • 54
  • 36
    Although this seems like a solution, it really should not be treated as one. Rather then simply add ambiguity and hide transpiler errors (which this does), it is far better to actually fix them and get useful feedback from the console. – Parzh from Ukraine Nov 21 '17 at 16:40
  • 8
    This is just casting and hiding the problem. You need to potentially use polyfills in specific browsers, etc. This will result in errors running in some browsers – Tom McKearney Mar 19 '18 at 16:38
  • 4
    I would advice anyone looking here to scroll down a bit further where it explains what to add to your `tsconfig` which is a better solution than this one. – mesqueeb Feb 23 '19 at 08:01
137

This is caused by you using an ECMAScript 6 feature and targeting ECMAScript 5 or 3. Easiest fix is to set the right target, for example if you are using Grunt:

options: {
    target: 'es6'
}

of change the relevant property tab in Visual Studio, or manually by editing your .csproj file and finding the TypeScriptTarget element and changing to ES6, for example:

<TypeScriptTarget>ES6</TypeScriptTarget>

If you need to target ES5, then merely add the following to your TypeScript code

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

That merges the extra method in, solving the issue. More details here. You may need a polyfill though, depending on your browser compatibility requirements - for example this one from MDN:

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;
    };
  })();
}
Robert MacLean
  • 38,975
  • 25
  • 98
  • 152
  • 5
    @JoeKeene This answer doesn't solve the problem in the best way as for TS 2.0+. If you're targeting ES5 then you should use the `--lib es2015` compiler option. My issue with the approach above is that if you `declare` the `Object.assign` function instead of using the built-in declaration then you won't get proper typing and documentation. They added the `--lib` option so you don't have to re-declare interfaces that are already part of the standard. – Rico Kahler Feb 02 '17 at 17:43
  • For this to work I had to add the interface declaration to a typings (`.d.ts`) file, rather than a typescript (`.ts`) file. – Mike Chamberlain Mar 07 '17 at 22:48
  • I changed `"target": "es5",` to `"target": "es6",` in `tsconfig.json`. and it worked (y) – theapache64 Jun 11 '18 at 15:21
  • 1
    For `Object.values`, it must be `"target": "es2017"`, since this is the top search result for the same error code. – NobleUplift Jul 06 '18 at 17:30
3

You can use spread operator as in ES6

const obj = {...this.success,...success.json()};

Fahd Allebdi
  • 354
  • 4
  • 7
1

I've added typings:

typings install dt~es6-shim --global --save
Sergejs
  • 2,540
  • 6
  • 32
  • 51
1

Why not use the spread operator?

return {this.success, ...success.json() || {}};

Dave
  • 1,356
  • 10
  • 15
  • Definitely preferable to use spread but can't in some of the scenarios `Object.assign` covers as the latter accepts an arbitrary number of objects. `return Object.assign({}, ...arrayOfObjects);`. – Aluan Haddad Sep 25 '20 at 15:02
0

I faced this issue when testing a React application with Jest using @testing-library/react. The fix for me was to add the following to my setupTests.ts:

declare global {
    interface Object {
        /**
         * Returns an array of values of the enumerable properties of an object
         * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
         */
        values<T>(o: { [s: string]: T } | ArrayLike<T>): T[];

        /**
         * Returns an array of values of the enumerable properties of an object
         * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
         */
        values(o: {}): any[];

        /**
         * Returns an array of key/values of the enumerable properties of an object
         * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
         */
        entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][];

        /**
         * Returns an array of key/values of the enumerable properties of an object
         * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
         */
        entries(o: {}): [string, any][];
    }
}
Liran H
  • 9,143
  • 7
  • 39
  • 52
0

I have faced the same issue! Changing the compilerOptions didn't work in my code.Then I just tried with bracket notation, like this:

Object['assign'](this.success, success.json())
just me
  • 1
  • 1