我正在尝试理解TypeScript装饰器(特别是属性),并根据我看到的一些示例提出了以下代码:
decorator.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');
我的问题是,当我尝试运行时,我得到:
TypeError:无法读取未定义的属性“firstName”
似乎this
的值未定义。我错过了什么?
作为参考,我的tsconfig.json
有:
"target": "es5"
"experimentalDecorators": true
"strict": false
更新8/27
似乎只有在装饰器位于不同的.ts
文件中时才会出现此问题。如果将装饰器放在另一个文件中并从另一个文件导入,则会发生错误。但是,将它们全部放在同一个文件中不会导致问题。我只是误解了this
如何被解释?
答案 0 :(得分:1)
tl; dr:我不确定为什么OP的配置不起作用;它现在看起来很漂亮。请参阅下面的一些蛮力测试。
我想知道你是不是以某种方式选错了tsconfig
。我看了your repo's tsconfig
,看起来很正确。有没有机会另一个配置文件感染这些运行?我看到there were no automated tests there。
我今天遇到了类似的问题,并以OP作为蓝图汇总a quick test。我提取了编译器选项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}`);
}
}
}
您可以看到完整版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.ts
Testing 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.ts
Testing 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.ts
Testing 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.ts
Testing 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.ts
Testing 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.ts
Testing 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
tsconfig
根据这些结果,看起来好像tsconfig
。
{
"compilerOptions": {
"target": "es5",
"module": "<not None>",
"experimentalDecorators": true,
"strict": false
}
}
2.4.2
和I'm using 2.7.2
。只是为了确保不是问题,I bumped my version down too。答案 1 :(得分:0)
'this'未定义,因为您没有正确配置属性描述符。
代替:
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
执行以下操作:
Object.defineProperty(target, key, {
get() {
// this is defined
},
set(value: any) {
// this is defined
},
enumerable: true,
configurable: true
});
我遇到了同样的问题,上面的解决方案解决了它。
答案 2 :(得分:0)
您可以尝试以下操作:
代替
function logProperty(target: any, key: string) {
...
}
使用:
const logProperty = (target: any, key: string) => {
...
}
因为=>
的{{1}}就在外面,所以可以得到它。
希望对您有所帮助!