jjzjj

javascript - “this”在 TypeScript 属性装饰器中未定义

coder 2024-07-26 原文

我试图理解 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: Cannot read property 'firstName' of undefined

this 的值似乎未定义。我错过了什么?

作为引用,我的 tsconfig.json 有:

"target": "es5"
"experimentalDecorators": true
"strict": false

8 月 27 日更新 似乎只有当装饰器位于不同的 .ts 文件中时才会出现此问题。如果将装饰器放在不同的文件中并从另一个文件中导入它,则会发生错误。但是,将它们全部放在同一个文件中不会导致问题。我只是误解了 this 的解释方式吗?

最佳答案

tl;dr:我不确定为什么 OP 的配置不起作用;它现在似乎工作得很好。请参阅下面的一些暴力测试。

猜猜

我想知道您是否以某种方式选择了错误的 tsconfig。我看过 your repo's tsconfig它看起来是正确的。是否有可能另一个配置文件感染了这些运行?我看到 there were no automated tests there .

测试

我今天遇到了类似的问题,拼凑了a quick test使用 OP 作为蓝图。我提取了编译器选项 from the official docs .

装饰器.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
  }
}

最后的笔记

  • 我没有尽可能多地测试编译器选项。如果有兴趣,我可以稍后更新存储库。
  • 对于 OP 的问题,我仍然没有一个好的答案,这让我很困扰。
  • 我也检查了 TS 版本。 OP was using 2.4.2I'm using 2.7.2 .只是为了确保这不是问题所在,I bumped my version down too .

关于javascript - “this”在 TypeScript 属性装饰器中未定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45830878/

有关javascript - “this”在 TypeScript 属性装饰器中未定义的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  3. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  4. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  5. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  6. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  7. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  8. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  9. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  10. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

随机推荐