Search code examples
typescriptngrxngrx-store

Can't use Object Spread with TypeScript and @ngrx


I'm trying to use Object Spread on my reducer with @ngrx and Angular with TypeScript, however, I keep getting this error in the console:

ReferenceError: __assign is not defined

This is my code:

case INCREMENT: {
    return state = {
        ...state,
        counter: state.counter++
    }
}

But if I do as the code below, I can run the code just fine:

case INCREMENT: {
    return Object.assign({}, state, {
        counter: state.counter++
    }
}

I've read in another question that this may be related to the typescript version, but I'm using "typescript": "~2.2.1".

Am I missing something?


Edit:

Adding tsconfig.js as requested in the comments.

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "noEmitHelpers": true,
        "noEmitOnError": true,
        "lib": [
            "es6",
            "dom",
            "es2015.iterable"
        ],
        "baseUrl": ".",
        "paths": {
            "*": [
                "./node_modules/tns-core-modules/*",
                "./node_modules/*"
            ]
        }
    },
    "exclude": [
        "node_modules",
        "platforms",
        "**/*.aot.ts"
    ]
}

Solution

  • To provide future functionality to older compile targets Typescript includes several helper functions alongside any code that needs them. Object spread and rest can use Object.assign when targeting ES6, but Object.assign isn't part of the ES5 spec so when targeting ES5 typescript needs to include an __assign helper function.

    By default, this helper function will be included anywhere its relevant. This can slightly inflate the generated output because these helper functions will be included multiple times even if the generated output would like to use a single global source. The typescript team provided the option of not emitting these helper functions alongside the source code so users wouldn't have the extra size and could include these functions globally or whenever appropriate themselves. Recently they introduced tslib as a better solution. This is an external library you can include that will provide the helper functions but because it's registere as its own package in one place bundlers will be able to include it only once in the final bundle.

    This is why I asked for your tsconfig.json. You have turned off the emission of these helpers and you are using ES5. You will need to make sure the helper is there somehow. You can either:

    1. Remove the noEmitHelpers: true line from the tsconfig
    2. Provide the _assign function (and others) in scope at the time of execution
    3. Use tslib and bundle it in correctly.

    1 is the simplest option and is a two second fix that will work. 3 is a good long term solution.

    I'd say go for option 1 unless you have a really good reason not to. If your bundle size is being affected by the helpers or you want to, option 3 is good. Option 2 is the worst of both worlds and is redundant since you have 3.

    You can keep noEmitHelpers: true but you should include importHelpers: true.