'this' is Undefined in TypeScript Property Decorator 'this' is Undefined in TypeScript Property Decorator typescript typescript

'this' is Undefined in TypeScript Property Decorator


tl;dr: I'm not sure why OP's config didn't work; it seems to work beautifully now. See below for some brute-force testing.

Guess

I'm wondering if you were somehow picking up the wrong tsconfig. I've looked at your repo's tsconfig and it looks correct. Is there any chance another config file was infecting those runs? I see there were no automated tests there.

Testing

I ran into a similar issue today and threw together a quick test using OP as a blueprint. I pulled compiler options from the official docs.

decorators.ts

export function logProperty(target: any, key: string) {    let val = this[key];    const getter = () => {        console.log(`Get: ${key} => ${val}`);        return val;    };    const setter = (newVal) => {        console.log(`Set: ${key} => ${newVal}`);        val = newVal;    };    if (delete this[key]) {        Object.defineProperty(target, key, {            get: getter,            set: setter,            enumerable: true,            configurable: true        });    }}

main.ts

import { logProperty } from './decorators';class Person {    @logProperty    firstName: string;    @logProperty    lastName: string;    constructor(firstName: string, lastName: string) {        this.firstName = firstName;        this.lastName = lastName;    }}const foo = new Person('Foo', 'Bar');function logProperty2(target: any, key: string) {    let val = this[key];    const getter = () => {        console.log(`Get: ${key} => ${val}`);        return val;    };    const setter = (newVal) => {        console.log(`Set: ${key} => ${newVal}`);        val = newVal;    };    if (delete this[key]) {        Object.defineProperty(target, key, {            get: getter,            set: setter,            enumerable: true,            configurable: true        });    }}class Person2 {    @logProperty2    firstName: string;    @logProperty2    lastName: string;    constructor(firstName: string, lastName: string) {        this.firstName = firstName;        this.lastName = lastName;    }}const foo2 = new Person2('Foo', 'Bar');

index.ts

import * as assert from "assert";import * as shelljs from "shelljs";const MODULE_GENERATION = [    "CommonJS",    "AMD",    "System",    "UMD",    "ES6",    "ES2015",    "ESNext",];const TARGETS = [    "ES5",    "ES2015",    "ES2016",    "ES2017"]shelljs.exec("tsc --target 'ES5' --module 'None' --strict main.ts", { silent: true });assert.ok(shelljs.error());shelljs.exec("tsc --target 'ES5' --module 'None' main.ts", { silent: true });assert.ok(shelljs.error());for (const moduleGeneration of MODULE_GENERATION) {    console.log(`Testing module generation: ${moduleGeneration}`);    for (const target of TARGETS) {        console.log(`  Building for ${target}`);        for (const strict of [true, false]) {            console.log(`    Strict mode: ${strict ? 'en' : 'dis'}abled`)            const command = (                `tsc` +                ` --module '${moduleGeneration}'` +                ` --experimentalDecorators` +                ` --target '${target}'` +                ` ${strict ? "--strict" : ""}` +                ` main.ts`            );            const output = shelljs.exec(                command,                { silent: true },            );            let symbol;            if (strict) {                assert.ok(shelljs.error());                symbol = '✖'            } else {                assert.strictEqual(0, output.code);                symbol = '✓'            }            console.log(`      ${symbol} ${command}`);        }    }}

Results

You can see the full build on Travis.

Testing module generation: CommonJS  Building for ES5    Strict mode: enabled      ✖ tsc --module 'CommonJS' --experimentalDecorators --target 'ES5' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'CommonJS' --experimentalDecorators --target 'ES5'  main.ts  Building for ES2015    Strict mode: enabled      ✖ tsc --module 'CommonJS' --experimentalDecorators --target 'ES2015' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'CommonJS' --experimentalDecorators --target 'ES2015'  main.ts  Building for ES2016    Strict mode: enabled      ✖ tsc --module 'CommonJS' --experimentalDecorators --target 'ES2016' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'CommonJS' --experimentalDecorators --target 'ES2016'  main.ts  Building for ES2017    Strict mode: enabled      ✖ tsc --module 'CommonJS' --experimentalDecorators --target 'ES2017' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'CommonJS' --experimentalDecorators --target 'ES2017'  main.tsTesting module generation: AMD  Building for ES5    Strict mode: enabled      ✖ tsc --module 'AMD' --experimentalDecorators --target 'ES5' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'AMD' --experimentalDecorators --target 'ES5'  main.ts  Building for ES2015    Strict mode: enabled      ✖ tsc --module 'AMD' --experimentalDecorators --target 'ES2015' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'AMD' --experimentalDecorators --target 'ES2015'  main.ts  Building for ES2016    Strict mode: enabled      ✖ tsc --module 'AMD' --experimentalDecorators --target 'ES2016' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'AMD' --experimentalDecorators --target 'ES2016'  main.ts  Building for ES2017    Strict mode: enabled      ✖ tsc --module 'AMD' --experimentalDecorators --target 'ES2017' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'AMD' --experimentalDecorators --target 'ES2017'  main.tsTesting module generation: System  Building for ES5    Strict mode: enabled      ✖ tsc --module 'System' --experimentalDecorators --target 'ES5' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'System' --experimentalDecorators --target 'ES5'  main.ts  Building for ES2015    Strict mode: enabled      ✖ tsc --module 'System' --experimentalDecorators --target 'ES2015' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'System' --experimentalDecorators --target 'ES2015'  main.ts  Building for ES2016    Strict mode: enabled      ✖ tsc --module 'System' --experimentalDecorators --target 'ES2016' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'System' --experimentalDecorators --target 'ES2016'  main.ts  Building for ES2017    Strict mode: enabled      ✖ tsc --module 'System' --experimentalDecorators --target 'ES2017' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'System' --experimentalDecorators --target 'ES2017'  main.tsTesting module generation: UMD  Building for ES5    Strict mode: enabled      ✖ tsc --module 'UMD' --experimentalDecorators --target 'ES5' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'UMD' --experimentalDecorators --target 'ES5'  main.ts  Building for ES2015    Strict mode: enabled      ✖ tsc --module 'UMD' --experimentalDecorators --target 'ES2015' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'UMD' --experimentalDecorators --target 'ES2015'  main.ts  Building for ES2016    Strict mode: enabled      ✖ tsc --module 'UMD' --experimentalDecorators --target 'ES2016' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'UMD' --experimentalDecorators --target 'ES2016'  main.ts  Building for ES2017    Strict mode: enabled      ✖ tsc --module 'UMD' --experimentalDecorators --target 'ES2017' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'UMD' --experimentalDecorators --target 'ES2017'  main.tsTesting module generation: ES6  Building for ES5    Strict mode: enabled      ✖ tsc --module 'ES6' --experimentalDecorators --target 'ES5' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'ES6' --experimentalDecorators --target 'ES5'  main.ts  Building for ES2015    Strict mode: enabled      ✖ tsc --module 'ES6' --experimentalDecorators --target 'ES2015' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'ES6' --experimentalDecorators --target 'ES2015'  main.ts  Building for ES2016    Strict mode: enabled      ✖ tsc --module 'ES6' --experimentalDecorators --target 'ES2016' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'ES6' --experimentalDecorators --target 'ES2016'  main.ts  Building for ES2017    Strict mode: enabled      ✖ tsc --module 'ES6' --experimentalDecorators --target 'ES2017' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'ES6' --experimentalDecorators --target 'ES2017'  main.tsTesting module generation: ES2015  Building for ES5    Strict mode: enabled      ✖ tsc --module 'ES2015' --experimentalDecorators --target 'ES5' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'ES2015' --experimentalDecorators --target 'ES5'  main.ts  Building for ES2015    Strict mode: enabled      ✖ tsc --module 'ES2015' --experimentalDecorators --target 'ES2015' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'ES2015' --experimentalDecorators --target 'ES2015'  main.ts  Building for ES2016    Strict mode: enabled      ✖ tsc --module 'ES2015' --experimentalDecorators --target 'ES2016' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'ES2015' --experimentalDecorators --target 'ES2016'  main.ts  Building for ES2017    Strict mode: enabled      ✖ tsc --module 'ES2015' --experimentalDecorators --target 'ES2017' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'ES2015' --experimentalDecorators --target 'ES2017'  main.tsTesting module generation: ESNext  Building for ES5    Strict mode: enabled      ✖ tsc --module 'ESNext' --experimentalDecorators --target 'ES5' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'ESNext' --experimentalDecorators --target 'ES5'  main.ts  Building for ES2015    Strict mode: enabled      ✖ tsc --module 'ESNext' --experimentalDecorators --target 'ES2015' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'ESNext' --experimentalDecorators --target 'ES2015'  main.ts  Building for ES2016    Strict mode: enabled      ✖ tsc --module 'ESNext' --experimentalDecorators --target 'ES2016' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'ESNext' --experimentalDecorators --target 'ES2016'  main.ts  Building for ES2017    Strict mode: enabled      ✖ tsc --module 'ESNext' --experimentalDecorators --target 'ES2017' --strict main.ts    Strict mode: disabled      ✓ tsc --module 'ESNext' --experimentalDecorators --target 'ES2017'  main.ts

Solid tsconfig

Based on those results, it looks like this is an okay tsconfig.

{  "compilerOptions": {    "target": "es5",    "module": "<not None>",    "experimentalDecorators": true,    "strict": false  }}

Final Notes

  • I didn't test as many compiler options as I could have. If there's interest, I can update the repo later.
  • I still don't have a good answer for OP's issue and that bothers me.
  • I did check TS version as well. OP was using 2.4.2 and I'm using 2.7.2. Just to make sure that wasn't the issue, I bumped my version down too.


'this' is undefined because you are not properly configuring the property descriptor.

Instead of:

Object.defineProperty(target, key, {      get: getter,      set: setter,      enumerable: true,      configurable: true    });

Do something like:

Object.defineProperty(target, key, {      get() {         // this is defined      },      set(value: any) {         // this is defined      },      enumerable: true,      configurable: true    });

I had the same issue and the solution above solves it.


you can try this:

instead of

function logProperty(target: any, key: string) { ...}

using:

const logProperty = (target: any, key: string) => { ...}

because => 's this just outside, so it can get it.hope it's helpful!