Typescript: dekorator

Dibuat pada 7 Mar 2015  ·  139Komentar  ·  Sumber: microsoft/TypeScript

ES7 proposal

Proposal ES7 untuk dekorator dapat ditemukan di sini: https://github.com/wycats/javascript-decorators
Proposal ES7 menjadi dasar dari proposal ini. Di bawah ini adalah catatan tentang bagaimana sistem tipe

Target dekorator:

Konstruktor kelas

@F("color")
<strong i="12">@G</strong>
class Foo {
}

desugars ke:

var Foo = (function () {
    function Foo() {
    }
    Foo = __decorate([F("color"), G], Foo);
    return Foo;
})();

Metode

class Foo {
  @F(color)
  <strong i="19">@G</strong>
  bar() { }
}

desugars ke:

var Foo = (function () {
    function Foo() {
    }
    Foo.prototype.bar = function () {
    };
    Object.defineProperty(Foo.prototype, "bar", __decorate([F(color), G], Foo.prototype, "bar", Object.getOwnPropertyDescriptor(Foo.prototype, "bar")));
    return Foo;
})();

Metode statis

class Foo {
    @F("color")
    <strong i="26">@G</strong>
    static sMethod() {}
}

desugars ke:

var Foo = (function () {
    function Foo() {
    }
    Foo.sMethod = function () {
    };
    Object.defineProperty(Foo, "sMethod", __decorate([F("color"), G], Foo, "sMethod", Object.getOwnPropertyDescriptor(Foo, "sMethod")));
    return Foo;
})();

Properti

class Foo {
    @F("color")
    <strong i="33">@G</strong>
    prop: number;
}

desugars ke:

var Foo = (function () {
    function Foo() {
    }
    __decorate([F("color"), G], Foo.prototype, "prop");
    return Foo;
})();

Parameter formal Metode/Aksesor

class Foo {
    method(<strong i="40">@G</strong> a, @F("color") b) {}
}

desugars ke:

var Foo = (function () {
    function Foo() {
    }
    Foo.prototype.method = function (a, b) {
    };
    __decorate([G], Foo.prototype, "method", 0);
    __decorate([F("color")], Foo.prototype, "method", 1);
    return Foo;
})();

Di mana __decorate didefinisikan sebagai:

var __decorate = this.__decorate || function (decorators, target, key, value) {
    var kind = typeof (arguments.length == 2 ? value = target : value);
    for (var i = decorators.length - 1; i >= 0; --i) {
        var decorator = decorators[i];
        switch (kind) {
            case "function": value = decorator(value) || value; break;
            case "number": decorator(target, key, value); break;
            case "undefined": decorator(target, key); break;
            case "object": value = decorator(target, key, value) || value; break;
        }
    }
    return value;
};

Tanda tangan dekorator:

Seorang dekorator yang valid harus:

  1. Ditetapkan ke salah satu jenis Dekorator (ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator) seperti yang dijelaskan di bawah ini.
  2. Mengembalikan nilai (dalam kasus dekorator kelas dan dekorator metode) yang dapat ditetapkan ke nilai yang didekorasi.
declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;
declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
declare type ParameterDecorator = (target: Function, propertyKey: string | symbol, parameterIndex: number) => void;

Catatan:

  • Mendekorasi deklarasi fungsi tidak diperbolehkan karena akan memblokir pengangkatan fungsi ke atas cakupan, yang merupakan perubahan signifikan dalam semantik.
  • Ekspresi fungsi dekorasi dan fungsi panah tidak didukung. Efek yang sama dapat dicapai dengan menerapkan fungsi dekorator sebagai var x = dec(function () { });
  • Dekorasi parameter formal fungsi saat ini bukan bagian dari proposal ES7.
  • Dekorator tidak diperbolehkan saat menargetkan ES3
Committed ES Next Fixed Suggestion

Komentar yang paling membantu

Fungsi dekorasi sangat dibutuhkan tentunya.
Apakah ada juga rencana untuk mendekorasi objek lain dalam kode?

Semua 139 komentar

Permisi dari apa yang saya pahami tentang spesifikasi, kami tidak akan dapat melakukan:

<strong i="6">@F</strong>
function test() {
}

Apakah saya benar ?

Bagaimana cara kerja serialisasi tipe dengan argumen istirahat?

@F()  
class Foo {  
    constructor(...args: string[]) {  
    }  
}  

function F(<strong i="6">@paramterTypes</strong> types?: Function[]) {  
    return function (target) {  
        target.paramterTypes = types; // ???  
    }  
}

Menggunakan dekorator tampaknya cukup mudah, tetapi saya menemukan bagian tentang mendeklarasikannya membingungkan. C.4 mengatakan dekorator perlu dianotasi dengan @decorator , tetapi tidak satu pun dari contoh yang benar-benar menunjukkan hal ini terjadi.

Apakah pabrik dekorator dimaksudkan sebagai kelas yang mengimplementasikan antarmuka yang ditemukan di B?

Apa aturan untuk menyempurnakan interpretasi CoverMemberExpressionSquareBracketsAndComputedPropertyName?

Saya perhatikan banyak pengetikan memiliki Function | Object di berbagai titik, tetapi ini akan berubah menjadi Objek pada waktu pemeriksaan tipe. Apa alasan untuk memiliki Fungsi di sana?

Saya tidak tergila-gila dengan istilah DecoratorFunction vs DecoratorFactory. Saya lebih suka mengikuti nomenklatur generator, yang memiliki Generator dan GeneratorFunction. Dengan skema ini, kami akan mengganti nama DecoratorFunction menjadi Decorator, dan DecoratorFactory menjadi DecoratorFunction.

Untuk ekspor yang dihias, untuk apa [lookahead ≠ @] ? Bisakah HoistableDeclaration dan ClassDeclaration benar-benar dimulai dengan @ ?

Ini adalah duplikat dari #1557

Ini sebenarnya bukan penipuan, karena #1557 adalah untuk desain yang berbeda. Masalah ini untuk desain dekorator yang sedang diterapkan sekarang.

Kesalahanku.

Untuk dekorator pada ekspresi fungsi, tidak bisakah kita melakukan sesuatu seperti:

@F("color") <strong i="6">@G</strong> 
function myFunc() {
   doSomething();
}

diubah menjadi:

var _t = function() {
   doSomething();
}
_t = F("color")(_t = G(_t) || _t) || _t;  

function myFunc() {
  return _t.apply(this, arguments)
}

Agak merepotkan beberapa orang untuk memperbaiki setiap fungsi seperti:

const myFunc = function () {}

Anda kehilangan pengangkatan, dan function.name

Implementasi ditambahkan dalam PR #2399

Pembaruan: Proposal diperbarui, dan menambahkan tautan ke dekorator JavaScript @wycats ES7.

sedih bahwa itu menjadi satu-satunya kelas ...
Juga bagaimana dengan dekorator ambient apakah mereka keluar dari ruang lingkup?

@fdecampredon dengan proposal Anda untuk fungsi, sepertinya Anda masih kehilangan pengangkatan.

@JsonFreeman kenapa? jika Anda memasukkan _t di bagian atas file ?

import something from 'something';

myFunc(something.something());

@F("color") <strong i="8">@G</strong> 
function myFunc() {
  doSomething()
}
import something from 'something';

var _t = function() {
   doSomething();
}
_t = F("color")(_t = G(_t) || _t) || _t;  

myFunc(something.something());

function myFunc() {
  return _t.apply(this, arguments)
}

Juga bahkan jika proposal saya memiliki banyak masalah, saya sangat ingin dapat menggunakan dekorator pada fungsi (bahkan jika saya harus menggunakan fungsi yang ditetapkan variabel) dan kehilangan pengangkatan.
Kasus seperti ini Intisari tampaknya merupakan kasus penggunaan dekorator yang cukup bagus untuk fungsi dan kelas (terutama ditambah dengan dekorator ambient jika mereka masih berada dalam ruang lingkup)

@fdecampredon ini tidak berfungsi untuk kasus umum, karena dekorator adalah ekspresi itu sendiri. misalnya

myFunc();  // assumes function declaration is hoisted

var dec = (t) => t; // defininig a decorator

<strong i="7">@dec</strong>
function myFunc() {}

jika Anda mengangkat deklarasi fungsi dan aplikasi dekorator maka Anda merusak dekorator. jika Anda hanya mengangkat deklarasi fungsi, tetapi bukan aplikasi dekorator, Anda dapat menyaksikan fungsi tersebut dalam keadaan tidak didekorasi. tidak ada solusi yang menarik di sini.

ini adalah masalah yang sama dengan klausa perpanjangan deklarasi kelas, yang dalam ES6 adalah ekspresi. hasilnya tidak mengangkat deklarasi kelas, hanya simbol (mirip dengan deklarasi var, tetapi bukan deklarasi fungsi)

Oups tidak kepikiran terima kasih @mhegazy.
Namun mengapa bagian fungsi telah sepenuhnya meninggalkan proposal @jonathandturner asli memiliki aturan:

decorated function declarations cannot be hoisted to the containing scope

Kehilangan pengangkatan tentu merupakan kelemahan, tetapi saya merasa dapat merusaknya untuk mengubahnya menjadi fitur kelas saja ketika itu akan memiliki kasus penggunaan untuk konstruksi lain.

Mari kita lihat apa yang disiratkan oleh rangkaian kendala yang diinginkan:

  • fungsi yang didekorasi harus diangkat
  • fungsi harus didekorasi segera setelah tersedia - oleh karena itu aplikasi dekorator harus diangkat
  • dekorator harus didefinisikan sebelum diterapkan - oleh karena itu definisi dekorator itu sendiri (atau semua entitas yang dirujuk oleh ekspresi dekorator) harus diangkat
  • ekspresi dekorator dievaluasi di tempat itu diterapkan secara leksikal - oleh karena itu aplikasi tidak dapat diangkat

Satu-satunya resolusi yang dapat saya lihat untuk ini adalah sebagai berikut: Untuk dekorator fungsi, kami hanya mengizinkan sesuatu dalam bentuk @identifier . Kami tidak mengizinkan ekspresi sisi kiri. Selain itu, pengidentifikasi harus menjadi referensi langsung ke deklarasi fungsi (termasuk fungsi yang didekorasi). Semua dekorasi fungsi yang terjadi di ruang lingkup harus dipancarkan di bagian atas ruang lingkup, sesuai urutan penerapannya.

Masalah melanggar aturan mengangkat adalah bahwa hal itu mengejutkan. Jika Anda menulis javascript untuk sementara waktu, Anda mengharapkan deklarasi fungsi tersedia sebelum dideklarasikan secara leksikal; sekarang dengan menambahkan penanda sintaksis yang tampaknya sederhana (dekorator), sifat dasar dari deklarasi fungsi ini diubah.

Karena itu, proposal ES7 masih dalam tahap awal, jadi saya berharap itu berkembang dan berkembang; sehingga dapat dibayangkan bahwa proposal akhir akan mencakup fungsi dalam beberapa bentuk.

Saya pikir mereka harus diangkat. Saya mengatakan bahwa satu-satunya dekorasi yang kami izinkan pada acara adalah dekorasi yang secara pasti dikibarkan sendiri. Yaitu pengidentifikasi yang mereferensikan deklarasi fungsi.

Tapi ada masalah lain di sini. Sebenarnya tidak mungkin untuk secara bersamaan mengangkat semua fungsi yang didekorasi dan memastikan bahwa mereka tidak diamati dalam keadaan tidak didekorasi. Masalahnya dapat dilihat dengan siklus dekorator.

<strong i="7">@dec1</strong>
function dec2(target: Function) {
   // Do stuff
}

<strong i="8">@dec2</strong>
function dec1(target: Function) {
   // Do stuff
}

Bahkan jika kedua fungsi diangkat, mana yang didekorasi terlebih dahulu? Jika dec2 didekorasi terlebih dahulu, maka dec1 tidak akan didekorasi dengan sendirinya pada saat diterapkan ke dec2.

Jadi kita harus memilih antara yang berikut:

  • Fungsi tidak diangkat
  • Fungsi yang tidak didekorasi diangkat, tetapi aplikasi dekorator tidak diangkat bersamanya.

Meskipun saya tidak menyukai salah satu dari ini, saya bahkan tidak berpikir ada hal lain yang mungkin.

Ini adalah proposal JS. jadi mesin tidak akan tahu apakah ekspresi mengacu pada deklarasi fungsi atau tidak, dengan analisis statis kami dapat mengetahuinya. pertimbangkan ini:

<strong i="6">@dec1</strong>
function dec2(target: Function) {
   // Do stuff
}

dec2 = undefined;

<strong i="7">@dec2</strong>
function dec1(target: Function) {
   // Do stuff
}

Ugh! Javascript tidak menjadi lebih sederhana lagi. :-)

Akan lebih mudah untuk mengaktifkannya hanya pada fungsi _expressions_:

const foo = <strong i="6">@decorator</strong> () => {
    // ...   
}
const bar = <strong i="7">@decorator</strong> function() {
    // ...
}

Ekspresi fungsi atau lambda tidak diangkat.

Apakah mungkin memiliki parameter seperti ini di dekorator di TypeScript 1.5.0-alpha ?

@dec1({key1: value1, key2, value2})
function dec2(target: Function) {
   // Do stuff
}

Oke tidak apa-apa, buat saja pabrik yang mengambil parameter dan mengembalikan fungsi dekorator yang sebenarnya.

Misalnya, dekorator kelas dengan parameter string:

function decoratorWithString(param: string) { // Decorator factory
    return function(target) { // Actual decorator
        // Do stuff with target and string parameter
    }
}

// Usage
@decoratorWithString('foobar')
class Foo {

}

Salam pembuka.

saya mencoba mencari cara untuk menulis dekorator yang akan mengambil tipe yang dideklarasikan dalam konstruktor.

inilah beberapa kode yang menggambarkan apa yang saya coba lakukan, tetapi sudah tertanam. saya membutuhkannya untuk menanggapi deklarasi konstruktor di kelas D

class A {
  public message = "identity: class A";
}

class B {
  public message = "identity: class B";
}

<strong i="8">@decoTest</strong>
class D {
  static metadata:Array<Function> = [];
  constructor(a: A, b: B) {
  }
}
describe("decorators", function() {
  it("should inject constructor types", function() {
    var d = new D(new A(), new B());
    expect(D.metadata.length).toBe(2);
  });
});


function decoTest<T>(target: T, ...rest) {
  target["metadata"].push(A, B); // how do i get this based on constructor ???
  return target;
}

Saya khawatir informasi jenis di luar cakupan fitur dekorator.
Anda dapat menggunakan ParameterDecorator pada setiap parameter untuk menambahkan informasi semacam itu.

Pengetikan atau implementasi ParameterDecorator kurang tepat, dari pengetikan targetnya adalah fungsi, tetapi saat menggunakan TypeScript, itu adalah objek prototipe.
Saya harus memberikan parameter target untuk mendapatkan tipe yang tepat:

function MyParameterDecorator (_target: Function, methodName: string, index: number) {
    const target = <InterfaceForMyUseCase><anyt>_target;
    // do stuff
}

Dari pada:

function MyParameterDecorator (target: InterfaceForMyUseCase, methodName: string, index: number) {
    // do stuff
}

wow - aturan dekorator parameter !!!!!!!!!!!!!!! lihat repo ini

inilah output dari menjalankan tes:

LOG: 'injectMe:'
LOG: '  type: class A'
LOG: '  type: class B'
LOG: '  some key'

dan kode :

module ParameterDecorators {
  class A {
    static typeName:string = "type: class A";
    public instanceTypeName = "instance: class A";
  }

  class B {
    static typeName:string = "type: class B";
    public instanceTypeName = "instance: class B";
  }

  @injectTest(A, B, "some key")
  class C {
    static injectMe: Array<any> = [];
    constructor(a: A, b: B) {
    }
  }

  function injectTest(...rest) {
    return function(target): void {
      target["injectMe"] = rest;
    }
  }

  describe("decorators", function() {
    it("should inject dependency-injection keys", function() {
      var c = new C(new A(), new B());
      console.log("injectMe:");
      for (let parm of C.injectMe) {
        if (typeof(parm) === "function") {
          console.log("\t" + parm["typeName"]);
        } else {
          console.log("\t" + parm)
        }
      }
    });
  });
}

Saya telah membuat pembungkus di sekitar express (tetapi kerangka kerja web apa pun dapat didukung, antarmuka adaptor ditentukan) dengan API berbasis dekorator: https://github.com/cybrown/web-decorators

Saya menggunakan ClassDecorator, ParameterDecorator dan MethodDecorator.

@cybrown Saya baru saja memperbarui tanda tangan untuk ParameterDecorator di #2635, yang sekarang di master.

@rbuckton Terima kasih, saya akan memperbaruinya besok di proyek saya.

Apakah mungkin untuk memiliki nama parameter di ParameterDecorator ?
Ini mungkin berguna karena menurut saya nama parameter mungkin separuh dari argumen pertama ParameterDecorator.
Selain itu, ini mungkin menjadi solusi untuk mangling nama parameter oleh minifiers.

saya telah diminta untuk mencapai ini:

@inject(A, B, "some key")
  class C {
    static injectMe: Array<any> = [];
    constructor(a: A, b: B) {
    }
  }

  function inject(...rest) {
    return function(target): void {
      target["inject"] = rest;
    }
  }

tetapi tanpa menentukan kunci di dekorator injeksi, tetapi sebaliknya meminta dekorator mengambil fungsi kelas konstruktor secara otomatis dengan sesuatu di sepanjang baris ini:

inject(<strong i="9">@parameterTypes</strong> types:Function[]){ ... }

saya mencari cara melakukan apa yang dijelaskan @jonathandturner di sini

@cmichaelgraham Ya memiliki informasi jenis runtime (rtti seperti yang dijelaskan dalam AtScript) akan luar biasa untuk penggunaan semacam itu, bahkan dalam fitur yang sepenuhnya terpisah seperti introspeksi.

@cmichaelgraham Kami sedang mengerjakan proposal untuk ES7 untuk menambahkan API metadata yang akan bekerja sama dengan dekorator. #2589 menambahkan dukungan eksperimental untuk proposal itu, tetapi membutuhkan polyfill terpisah untuk membaca metadata.

@rbuckton @cmichaelgraham Awalnya ada desain untuk dekorator TypeScript khusus yang akan memberi tahu kompiler untuk menyuntikkan tipe ke dekorator, berdasarkan target yang didekorasi. Saya pikir itu @parameterTypes Apakah saya benar dalam berpikir bahwa fitur itu sedang dihapus demi metadata api yang lebih umum? Jika demikian, saya akan mendukungnya.

Bisakah Anda berbicara sedikit tentang status itu sehubungan dengan TypeScript. Apakah itu direncanakan untuk rilis 1.5? Jika demikian, seperti apa tampilan opsi kompiler? Satu hal yang akan berguna adalah membuat kompiler secara otomatis menghasilkan jenis metadata untuk tanda tangan konstruktor saja.

@EisenbergEffect Dekorator adalah bagian dari 1.5, Anda dapat mulai menggunakannya dengan rilis terbaru kami 1.5-alpha .

Adapun dukungan meta data. Desing telah berubah sejak proposal asli untuk @paramtypes . desain baru menggunakan proposal Reflect.metada. Lihat #2589 untuk detail selengkapnya tentang cara kerjanya. juga @rbuckton memiliki pollyfill untuk menggunakan metadata di sini: https://github.com/rbuckton/reflectDecorators

@mhegazy saya tahu itu. Lihat di sini: http://blog.durandal.io/2015/04/09/aurelia-update-with-decorators-ie9-and-more/ :smile:

Saya juga akrab dengan proposal metadata. Saya telah memberikan umpan balik tentang itu. Saya hanya ingin tahu apakah ide asli @parameterTypes telah dihapus.

terima kasih @EisenbergEffect untuk berbagi. :+1:

Ya. satu-satunya masalah dengan @paramtypes itu membuat emisi diarahkan oleh sistem tipe, dan membutuhkan informasi program global. Ini merusak skenario untuk transpilasi modul tunggal (lihat #2499). Pilihan lainnya adalah meletakkannya di situs panggilan, yang menambahkan banyak pekerjaan pada pengguna dekorator alih-alih penulis. Jadi kami kembali ke papan gambar dan mendarat di pendekatan Reflect.metadata sebagai gantinya.

jika Anda juga melihat versi proposal sebelumnya, kami harus menghapus dekorator ambient/design-time untuk alasan yang sama.

Terima kasih telah mengklarifikasi. Itu semua masuk akal. Adakah ide jika pendekatan berbasis Reflect akan mendarat di 1,5?

Ya. saat ini dalam master. itu harus tersedia di rilis berikutnya. saat ini merupakan fitur keikutsertaan menggunakan tanda eksperimental --emitDecoratorMetadata ; dan itu hanya menambahkan metadata ke entitas yang didekorasi.

"itu hanya menambahkan metadata ke entitas yang didekorasi" Bisakah Anda memperluas ide itu? Apakah ada dekorator khusus yang terlibat? Atau apakah itu menambahkannya ke apa pun dengan dekorator apa pun? Dengan kata lain, jika pengembang menggunakan dekorator inject Aurelia, apakah itu akan memicu kompiler untuk menghasilkan metadata?

jika pengembang menggunakan dekorator injeksi Aurelia, apakah itu akan memicu kompiler untuk menghasilkan metadata?

Ya.

yang saya maksud adalah:

<strong i="9">@inject</strong>
class Foo {
    constructor(a: number, b: string) {}
}

class Bar {
    constructor(a: number, b: string) {}
}

dengan --emitDecoratorMetadata kompilator akan memancarkan metadata tipe (yaitu panggilan ke reflect.metadata('desing:paramtypes', [Number, String]) ) untuk Foo tetapi _not_ Bar .

Itu akan berhasil untuk kita. Kami akan menyiapkan dukungan untuk api Reflect.metadata untuk rilis berikutnya, kemungkinan besar minggu depan. Terimakasih atas klarifikasinya!

jadi apa yang dipancarkan untuk ini?

``` bahasa = javascript
@menyuntikkan
kelas Foo {
konstruktor(a: A, b: B) {}
}

bilah kelas {
konstruktor(a: angka, b: B) {}
}

would it be (for Foo):

``` javascript
reflect.metadata('desing:paramtypes', [A, B])

@cmichaelgraham Ya, kira-kira itulah yang dihasilkan.

keren gila!!!!

menggunakan gulp-typescript untuk membangun repo ini - (kerja bagus @ivogabe)

perintah gulpfile build-ts (perhatikan opsi emitDecoratorMetadata ):

gulp.task('build-ts', function () {
    var tsResult = gulp.src([
        './views/*.ts',
        './typings/**/*.d.ts',
        './*.ts'
        ],
        {base: "."})
    .pipe(ts({
         typescript: require('typescript'),
         declarationFiles: false,
         noExternalResolve: true,
         target: "es5",
         module: "amd",
         emitDecoratorMetadata: true
    }));

    return merge([
        tsResult.dts.pipe(gulp.dest('.')),
        tsResult.js.pipe(gulp.dest('.'))
    ]);
});

ternyata app.ts

import {inject} from 'aurelia-framework';
import {Router} from 'aurelia-router';
import 'bootstrap';
import 'bootstrap/css/bootstrap.css!';

@inject(Router)
export class App {
  public router;
  constructor(router:Router) {
    this.router = router;
    this.router.configure(config => {
      config.title = 'Aurelia';
      config.map([
        { route: ['','welcome'],  moduleId: './welcome',      nav: true, title:'Welcome' },
        { route: 'flickr',        moduleId: './flickr',       nav: true },
        { route: 'child-router',  moduleId: './child-router', nav: true, title:'Child Router' }
      ]);
    });
  }
}

menjadi app.js

var __decorate = this.__decorate || (typeof Reflect === "object" && Reflect.decorate) || function (decorators, target, key, desc) {
    switch (arguments.length) {
        case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
        case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
        case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
    }
};
var __metadata = this.__metadata || (typeof Reflect === "object" && Reflect.metadata) || function () { };
define(["require", "exports", 'aurelia-framework', 'aurelia-router', 'bootstrap', 'bootstrap/css/bootstrap.css!'], function (require, exports, aurelia_framework_1, aurelia_router_1, , ) {
    var App = (function () {
        function App(router) {
            this.router = router;
            this.router.configure(function (config) {
                config.title = 'Aurelia';
                config.map([
                    { route: ['', 'welcome'], moduleId: './welcome', nav: true, title: 'Welcome' },
                    { route: 'flickr', moduleId: './flickr', nav: true },
                    { route: 'child-router', moduleId: './child-router', nav: true, title: 'Child Router' }
                ]);
            });
        }
        App = __decorate([
            aurelia_framework_1.inject(aurelia_router_1.Router), 
            __metadata('design:paramtypes', [aurelia_router_1.Router])
        ], App);
        return App;
    })();
    exports.App = App;
});

minat khusus adalah metadata tipe yang dipancarkan tentang parameter konstruktor:

        App = __decorate([
            aurelia_framework_1.inject(aurelia_router_1.Router), 
            __metadata('design:paramtypes', [aurelia_router_1.Router])
        ], App);

jadi secara teori, Anda dapat mengubah fungsi dekorator injeksi untuk menyuntikkan kelas yang tepat tanpa menentukannya dalam injeksi, tetapi sebaliknya menentukan jenis dalam konstruktor :)

@cmichaelgraham Kami dapat dengan mudah mengaktifkan ini hari ini tanpa mengubah kerangka kerja. Perpustakaan DI dari Aurelia memiliki pengait container.addParameterInfoLocator . Anda memberikannya fungsi yang dapat mengambil tipe dan mengembalikan dependensinya. Untuk rilis berikutnya (minggu depan), kami dapat menambahkan ini ke konfigurasi inti sehingga mudah bagi pengembang TypeScript untuk mengaktifkannya. Saya akan memasukkannya ke dalam rilis minggu ini, tetapi saya belum menyadari bahwa ini telah diubah.

@EisenbergEffect brilian!! :+1:

Saya menggunakan anotasi untuk menandai properti suatu objek sebagai yang dapat diamati, yang mengubah primitif menjadi objek yang dapat diamati (bagi mereka yang tertarik, https://github.com/mweststrate/MOBservable/commit/8cc7fc0e20c000db660037c8b5c9d944fe4155d9).

Namun, terutama untuk properti, rasanya agak tidak wajar bahwa anotasi diterapkan ke prototipe, dan bukan di konstruktor kelas itu sendiri, ini berarti sulit untuk mendapatkan nilai awal, atau bahkan this . Solusi untuk itu adalah membuat properti, dan dalam pengambil/penyetelnya melakukan logika aktual yang seharusnya dilakukan anotasi, karena this dan nilainya tersedia saat itu.

Selain itu, fitur luar biasa!

Menggunakan Metadata Reflection API, saya dapat melakukan injeksi ketergantungan properti sederhana.
Anda dapat memeriksa perubahan yang diperlukan di sini https://github.com/matjaz/property-DI/commit/2b4835e100b72d954b57d0e656ea524539ac17eb.

Bukankah dekorator __metadata dalam kode yang dihasilkan harus dipanggil terlebih dahulu? Saya ingin membuat deokrator sederhana menggunakan metadata kelas, tetapi __metadata('design:paramtypes', [TYPES....]) dipanggil sebagai yang terakhir, jadi saya tidak bisa mendapatkan data ini dari Reflect

@ufon dapatkah Anda membagikan kode yang Anda lihat?

Tentu, di sini https://Gist.github.com/ufon/5a2fa2481ac412117532

EDIT:
buruk saya, ada beberapa kesalahan lain dalam kode saya, tidak bisa mendapatkan tipe bahkan setelah inisialisasi kelas

@ufon , saya tidak yakin saya melihat masalah itu. __metadata adalah item terakhir dalam daftar dekorator, ini berarti ini adalah yang pertama dieksekusi, dan pastinya sebelum inject dapat dieksekusi.

    House = __decorate([
        inject_1.inject, 
        __metadata('design:paramtypes', [Floor, String])
    ], House);

di mana definisi __decorate menggunakan pengurangan hak untuk mengeksekusi dekorator dalam urutan terbalik.

decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);

Ini untuk mencocokkan spesifikasi, bahwa dekorator (sebagai ekspresi) dievaluasi dalam urutan deklarasi, tetapi dieksekusi dalam urutan terbalik, memungkinkan dekorator luar untuk mengkonsumsi hasil dari dekorator dalam.

Saya mengerti, maaf mengganggu :) buruk saya, ada beberapa kesalahan lain dalam kode saya, tidak bisa mendapatkan tipe bahkan setelah inisialisasi kelas

bagaimana Anda menanyakan mereka? dan apakah Anda memiliki pollyfill untuk Reflect.metadata?

ditambah intinya...
Reflect.getMetadataKeys(Rumah);
ini menghasilkan array kosong..

Ya, saya membutuhkan paket 'reflect-metadata'

sepertinya polyfill kehilangannya, @rbuckton dapatkah Anda melihatnya.

Pikir saya mendapatkannya ...
membutuhkan dipindahkan setelah kode pembantu TypeScript

var __metadata = this.__metadata || (typeof Reflect === "object" && Reflect.metadata) || function () { };
require('reflect-metadata');

jadi, pada saat var __metadata sedang diinisialisasi, polyfill belum dimuat

tetapi saya tidak bisa mendapatkan persyaratan ini sebelum kode yang dihasilkan

EDIT: memperbarui intinya.. ketika modul tunggal dikompilasi, tidak ada cara untuk memuat polyfill sebelum __metadata diselesaikan, karena kode yang dihasilkan TypeScript selalu dipindahkan ke bagian atas file

ooh.. ini masalah yang lebih besar. mencatat masalah #2811 untuk melacaknya

Sampai saat itu Anda memerlukan reflect-metadata di modul lain (Anda memerlukan dua file).
lihat https://github.com/matjaz/property-DI/

Tampaknya ada inkonsistensi doa yang membuat dekorator berkembang dengan parameter variabel/opsional cukup sulit dilakukan. Sebagai contoh:

<strong i="6">@F</strong>
prop: number;

@F()
prop: number;

Di yang pertama, F dipanggil dengan parameter (target, propertyName, propertyDescriptor) sedangkan di yang terakhir, F dipanggil dengan parameter () dan mengharuskan Anda memiliki fungsi internal yang dikembalikan yang pada gilirannya dipanggil dengan (target, propertyName dan propertiDescriptor).

_Asumsi_ saya adalah bahwa @F dan @F() akan setara dan oleh karena itu Anda hanya dapat melakukan panggilan jika dekorator mendukung 0 atau lebih parameter.

Ini sangat penting dalam kasus:

<strong i="13">@F</strong>  // Performs some default behaviour.
prop: number;

@F({ option: true }) // Performs some configured behaviour.
prop: number;

Ini dapat diatasi dengan hanya secara eksplisit memanggil @F() alih-alih @F tetapi mudah untuk membuat kesalahan itu dan kemudian menjadi bingung ketika dekorator Anda tidak berfungsi meskipun kelihatannya seharusnya.

Dalam hal ini saya ingin melakukan hal berikut:

export function F(options?: any): PropertyDecorator {
    return (target, name) => {
        // do something.
    }
}

dan selesai dengan itu, tetapi saya harus melakukan sesuatu seperti contoh kasar berikut:

export function F(...args: any[]): any {
   var func = (target, name) => {
      // do something.
   }

   if (args.length === 1) return func;
   else if (args.length === 2) func(args[0], args[1]);
}

Yang merupakan rasa sakit yang nyata.

@Tharaxis perilaku ini dirancang. @F dan @F() tidak setara. @F memanggil dekorator F , sedangkan @F() memanggil faktor dekorator F dengan daftar argumen kosong, dan kemudian menerapkan dekorator yang dihasilkan.

Masalahnya di sini adalah bahwa kompilator membandingkan tanda tangan pabrik dekorator F dengan declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void; yang akhirnya dapat dialihkan. saya pikir kita perlu pemeriksaan yang lebih kuat di sini untuk memastikan kita menangkap masalah ini. Saya telah login #3246 untuk memperbaikinya. Saya yakin Anda melakukan hal yang benar, dan kompiler harus menangkap penggunaan pabrik dekorator yang tidak valid.

@mhegazy Saya tidak yakin mengapa hal ini terjadi, apakah ada beberapa kasus penggunaan yang menghalangi seseorang membuat @F dan @F() setara, karena pada akhirnya keduanya merupakan permintaan identik dari fungsi dekorator , hanya salah satunya yang kebetulan juga menyertakan pemanggilan ke fungsi pabrik luar? Sepertinya prinsip paling tidak mengherankan dilanggar di sini karena ini jelas merupakan perilaku yang cukup mencengangkan dan saya tidak mengerti mengapa harus ada 2 cara untuk memanggil dekorator dari perspektif konsumen API.

Sementara saya mendapatkan bahwa dari perspektif JS ada perbedaan (dalam satu Anda melewati referensi fungsi F dan yang lain Anda menjalankan fungsi dan kemudian meneruskan referensi hasilnya sebagai dekorator), saya tidak yakin saya mengerti mengapa seseorang tidak bisa hanya memiliki dekorator yang diteruskan sebagai @F secara implisit cocok (dan memanggil) pabrik sebagai satu dengan daftar parameter kosong?

Kompiler tidak memiliki cara untuk mengetahui apakah itu pabrik atau dekorator. jika Anda memiliki tanda tangan ini:

declare function decoratorOrFactory (...args: any[]): any;

Apakah ini dekorator atau pabrik, haruskah disebut dengan argumen kosong atau tidak?

Yang paling dapat dilakukan oleh kompiler adalah memverifikasi bahwa tanda tangan cocok saat memanggilnya dengan satu atau lain cara, dan memberikan kesalahan jika tidak.

@rbuckton memiliki perbaikan untuk #3246 yang akan menandai kasus di mana dekorator Anda tidak digunakan sebagai pabrik, jadi pantau terus.

@mhegazy , apa yang saya katakan adalah bahwa penggunaan dekorator (yaitu @F atau @F() ) harus _always_ menjadi pemanggilan fungsi pabrik F, yang pada gilirannya mengembalikan tipe dekorator yang sesuai. Tidak ada representasi tingkat atas dari seorang dekorator tanpa pabrik enkapsulasi.

Dengan kata lain tanda tangan F selalu:

declare function F(...args: any[]): ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator;

Atau setara.

Kemudian pemanggilan @F dibuat setara dengan @F() oleh kompilator. Karena kedua tanda tangan @F dan @F() harus cocok dengan tanda tangan pabrik dalam beberapa bentuk, ini memecahkan masalah kebingungan pemanggilan. Hanya ada satu cara untuk memanggil dekorator!

Mengingat berikut ini:

declare function F(...args: any[]): PropertyDecorator {
    return (target, name) => {
        // do stuff.
    }
}

@F()
property: number;

dan

declare function F(target, name) { // Matches PropertyDecorator
    // do stuff.
}

<strong i="22">@F</strong>
property: number;

Mereka melakukan hal yang sama tetapi saya harus menyatakannya secara berbeda! Namun, mendeklarasikan F agar dapat eksis dalam dua arah sangatlah merepotkan dan membuat pembuatan parameter dan dokumentasi yang konsisten menjadi tidak mungkin. Anda memilih apakah dekorator Anda perlu menggunakan pabrik atau tidak, dan konsumen API Anda harus mengetahui perbedaan ini sebelumnya untuk menggunakannya.

@Tharaxis Jika saya melihat perpustakaan yang menyediakan F yang akan digunakan sebagai dekorator, saya benar-benar berharap @F dan @F() menjadi hal yang berbeda. Sama seperti yang saya harapkan C dan C() menjadi hal yang berbeda - yang pertama merujuk nilai, yang kedua memanggil nilai. @F menerapkan dekorator, @F() memanggil fungsi yang akan membuat dekorator. Itu bukan, dan tidak seharusnya, operasi yang sama.

@DavidSouther apakah ada alasan yang sah mengapa ini tidak bisa atau tidak seharusnya terjadi? Tidak ada perbedaan fungsional antara pemanggilan @F dan @F() tetapi ada perbedaan yang cukup besar antara cara mereka didefinisikan dan didokumentasikan, dan itu menambah kerumitan tambahan pada pemanggilan yang seharusnya tidak diperlukan.

Usulan saya adalah bahwa tidak boleh ada dua cara untuk mendefinisikan dekorator karena tidak perlu, dan tidak perlu mendefinisikan dekorator lebih dari satu cara.

Tidak ada perbedaan fungsional antara pemanggilan @F dan @F()

Saya pikir ini adalah poin utama pertengkaran. saya tidak berpikir ini benar. F adalah referensi ke suatu fungsi, F() adalah referensi ke nilai kembalian F ketika dipanggil dengan kumpulan argumen kosong (yaitu F.call(this, []) ); dan ini adalah dua hal yang secara fungsional dan konseptual berbeda.

@Tharaxis @F dan @F() adalah hal yang berbeda. Ada perbedaan dalam bagaimana mereka digunakan, perbedaan dalam bagaimana mereka didokumentasikan, dan perbedaan dalam doa mereka yang mutlak diperlukan.

Izinkan saya bertanya dengan cara yang berbeda: mengapa setiap fungsi dekorator harus menjadi pabrik? Menggunakan proposal Anda, tidak mungkin memiliki dekorator sederhana.

@mhegazy sementara saya akan mengakui bahwa opsi terakhir ( @F() ) menghasilkan pembuatan penutupan fungsional dan overhead tambahan melalui pembuatan fungsi dekorator yang terisolasi (dan digandakan) dan doa @F pada dasarnya melakukan terhadap referensi fungsi dekorator bersama, saya akan mengatakan bahwa isolasi melalui penutupan akan "lebih aman" dan lebih konsisten, mengurangi kemungkinan kejutan.

@DavidSouther Pertanyaan Anda tergantung pada apa yang Anda definisikan sebagai dekorator sederhana. Tidak ada yang menghalangi seseorang memiliki dekorator sederhana berupa:

declare function F(): PropertyDecorator {
    return (target, name) => {
        // do stuff
    }
}

Saya menemukan ini cukup minimal invasif karena hanya 2 baris lebih dari "sintaks sederhana" dan mendefinisikan lebih jelas apa doa dekorator yang tersedia. Selain itu, karena hanya ada satu cara untuk mendefinisikan dekorator (dan mari kita tidak mengabaikan nilai konsistensi), Anda mungkin akan membutuhkan kira-kira 2 detik lagi untuk menyelesaikan ini dibandingkan dengan "sintaks sederhana".

Selain itu masalah yang lebih bermasalah adalah sebagai berikut:

declare function F(options?: any): PropertyDecorator {
    return (target, name) => {
        // do stuff
    }
}

@F()
property1: number;

<strong i="15">@F</strong>
property2: number;

@F({ option: true })
property3: number;

salah satu dari benda ini tidak seperti yang lain. Penggunaan @F tidak akan berfungsi meskipun pada nilai nominalnya seharusnya. Ingatlah, berpura-puralah saya adalah seseorang yang tidak mengetahui seperti apa deklarasi yang mendasari F, tetapi ketahuilah bahwa F ada dan itu dapat mengambil serangkaian argumen opsional. Kemungkinan saya membuat kesalahan dengan @F tidak sepele di bawah mekanisme saat ini. Ini menempatkan tanggung jawab besar pada pengembang/dokumenter untuk memastikan bahwa konsumen mengetahui bahwa @F tidak akan berfungsi (tetapi mungkin @C akan berfungsi karena "berbeda" entah bagaimana).

Jika saya menginginkan dekorator "satu ukuran cocok untuk semua", di mana konsumen tidak perlu khawatir, saya harus melakukan hal mengerikan ini:

declare function F(...args: any[]): any {
    var decorator = (target, name) => {
        // do stuff
    }

    // Heaven forbid your decorator formal parameter list also can take 2 parameters.
    return (args.length === 2) ? decorator(args[0], args[1]) : decorator;
}

Yang sejujurnya cukup menghebohkan. Selain itu, saya kehilangan semua intellisense parameter berharga terhadap dekorator F karena sekarang harus digeneralisasi.

Ada banyak hal yang bisa dikatakan memiliki dekorator yang mudah dan konsisten untuk didefinisikan dan didokumentasikan. Jangan membodohi diri sendiri dengan berpikir bahwa setiap orang yang menggunakan kode kita akan memiliki pemahaman atau pemahaman yang sama dengan kita yang merupakan pencipta kode itu.

@Tharaxis Saya memikirkan ini sejak awal dalam desain untuk dekorator, dan saya mengerti poin spesifik Anda. Seperti yang @mhegazy dan @DavidSouther sebutkan sebelumnya di utas ini, perilaku ini konsisten dengan perilaku standar fungsi dalam JavaScript.

Anda benar bahwa setiap upaya untuk membuat fungsi yang dapat bertindak sebagai dekorator dan pabrik dekorator bisa agak rumit. Namun secara umum, mungkin lebih baik menggunakan praktik terbaik untuk selalu menggunakan pabrik dekorator, dan menyediakan aturan untuk linter untuk memastikan praktik ini diadopsi.

Juga, saya baru saja mengirimkan PR #3249 untuk mengatasi poin Anda sebelumnya mengenai inkonsistensi dalam pemeriksaan tipe untuk dekorator.

Hai @rbuckton ,

Saya salah satu dari pengguna dekorator yang tidak begitu paham yang disebutkan oleh @Tharaxis...

Saya kira pertanyaan yang saya miliki adalah haruskah dekorator konsisten dengan fungsi? Yaitu Dalam hal fungsi, mengembalikan this.f versus this.f() sangat masuk akal bagi saya karena terkadang saya menginginkan nilai, terkadang saya menginginkan hal yang menghasilkan nilai.

Dalam hal dekorator, bagi saya tampaknya tidak begitu jelas pada tingkat fitur bahasa. Saya ingin berargumen bahwa saya hanya ingin menerapkan dekorator @F , saya tidak benar-benar ingin tahu apakah itu telah diterapkan sebagai metode pabrik atau statis. Itu kecuali saya akan kehilangan beberapa kemampuan yang seharusnya dimiliki oleh dekorator.

Saya minta maaf jika di atas salah informasi atau bodoh, saya relatif baru di dunia javascript.

Terima kasih & semangat

Saya juga harus mengajukan pertanyaan itu - apakah masuk akal untuk mempertahankan paritas sintaksis dengan fungsi _if_ (dan hanya jika) tidak ada alasan nyata untuk melakukannya selain "karena itu didefinisikan menggunakan fungsi". Saya melihat Dekorator sebagai fitur yang sama sekali tidak terkait dengan fungsi yang hanya _terjadi_ untuk didefinisikan menggunakan mereka.

Saat ini fakta bahwa @F dan @F() tidak identik menyebabkan masalah berikut:

  • Pengembang perlu memahami perbedaan antara @F dan @F() dan mengapa terkadang ini berhasil dan mengapa terkadang ini tidak berhasil (dan kebutuhan untuk menggunakan @F vs. @F() dapat sepenuhnya spesifik kerangka/kode/penggunaan - oleh karena itu tidak konsisten dari sudut pandang konsumsi: Bayangkan declare function A(params?: any): ParameterDecorator vs declare function B(target, name) , @A tidak akan berfungsi, tetapi @A() akan, @B akan berfungsi tetapi @B() tidak akan, namun secara kognitif mereka adalah hal yang sama, aplikasi dekorator tanpa argumen).
  • Memecahkan masalah dari tingkat kode memerlukan solusi rumit yang menghilangkan kemampuan seseorang untuk mendokumentasikan sintaks permintaan Dekorator secara memadai.
  • Refactoring sedikit lebih berhasil jika Anda telah membuat 'dekorator mentah' ( @F ) dan sekarang Anda ingin menambahkan beberapa parameter (tetapi menjadikannya opsional untuk kompatibilitas mundur). Di bawah metode saat ini, semua @F berlaku sekarang perlu difaktorkan ulang menjadi @F() - beberapa di dalam kode yang mungkin tidak Anda akses - sementara pemanggilan implisit akan memungkinkan Anda tetap bekerja dan membatasi ubah ke kode Anda.

@Tharaxis Saya mengerti bahwa perbedaan antara @F dan @F() dapat menjadi beban kognitif yang tinggi pada konsumen. Namun, sepertinya Anda meminta kode yang dipancarkan, dan karena itu perilakunya, untuk berubah, sehingga keduanya berperilaku setara. Ini kemungkinan akan bertentangan dengan proposal ES7 untuk dekorator, karena kedua bentuk tersebut sangat tidak mungkin diperlakukan sama. Tidak baik jika ini mengarah pada divergensi.

Poin lainnya adalah bahwa kebingungan di sini mirip dengan kebingungan antara melewatkan fungsi sebagai panggilan balik, dan memanggil fungsi. Jika Anda memiliki ini

function callbackFactory() {
     return function(...args: any[]) { // do stuff };
}
function takesCallback(cb: (...args: any[]) => void) { }
takesCallback(callbackFactory());

Seorang pengguna mungkin bingung dan memanggil takesCallback(callbackFactory) tanpa memanggil callbackFactory . Ini benar-benar seperti kebingungan yang Anda tunjukkan dengan dekorator, tetapi jika bahasa menormalkan kedua bentuk ini untuk melakukan hal yang sama, akan ada kehilangan ekspresivitas. Terkadang perbedaan itu penting, dan perlu dipertahankan. Tidak yakin apakah ini juga berlaku untuk dekorator, tetapi secara teori pasti bisa.

@JsonFreeman Saya tidak terlalu mengerti argumen Anda. Anda mengatakan bahwa Anda tidak dapat membuat dekorator masuk akal sebagai entitas mereka sendiri karena proposal ES7 ada untuk dekorator, tetapi itulah masalahnya, dekorator ES7 hanyalah itu, _proposal_, dan sejauh yang saya ketahui, mereka' sebagian didasarkan pada kombinasi karya dekorator yang dijelaskan oleh Google dan Anda sendiri, benar? Belum ada yang diputuskan tentang cara kerjanya, dan kemungkinan proposal akan melalui _banyak_ iterasi sebelum disetujui, jadi mengapa tidak meminta mereka bekerja secara konsisten di TS dan kemudian (setidaknya coba) dapatkan berbagai pihak yang terlibat dalam proposal di balik ide tersebut, menggunakan pengalaman yang diperoleh di TS sebagai dasar? Ini bukan pertama kalinya TS mengimplementasikan fitur hanya untuk melakukan refactor nanti karena spesifikasi ES6 memerlukan perilaku yang sedikit berbeda. Anda akan _selalu_ mengalami masalah itu selama Anda melacak spesifikasi yang belum ada dan belum disepakati.

Adapun contoh Anda tentang fungsi, tampaknya sekali lagi kami menggabungkan fungsi dengan dekorator ketika mereka sebenarnya (dan seharusnya) konstruksi yang sama sekali berbeda. Ketika saya bekerja dengan sebuah fungsi dalam JavaScript, saya memahami bagaimana fungsi digunakan dan saya memahami perbedaan antara referensi fungsi dan pemanggilan fungsi (dan kapan saya mungkin ingin menggunakan satu vs. yang lain) - dan ketika saya menjelaskan sesuatu sebagai fungsi, tidak ada kebingungan tentang kegunaannya. Dekorator adalah fungsi _not_ dan tidak boleh mewarisi perilaku fungsi. Fungsi hanyalah metode di mana dekorator dibangun. Itu seperti mengatakan kelas adalah fungsi, yang tidak demikian, fungsi hanyalah cara yang kami jelaskan kelas sebelum ES6 karena tidak ada metode yang lebih jelas yang tersedia. Kelas tidak mengambil properti fungsi, Anda tidak dapat memanggil kelas seperti fungsi, tetapi Anda mendeklarasikannya menggunakan fungsi sebelum ES6.

Apapun, saya merasa bahwa saya telah kehabisan poin argumen saya tentang masalah ini. Aku hanya harus bekerja di sekitar pilihan. Dalam kode saya sendiri, saya akan selalu menggunakan pabrik demi konsistensi saya sendiri. Saya masih percaya memperlakukan dekorator secara harfiah sebagai fungsi kemungkinan akan menyebabkan banyak frustrasi di masa depan, tapi itu hanya saya.

@mhegazy Ini adalah masalah yang sama yang saya kemukakan di repo dekorator https://github.com/jonathandturner/decorators/issues/16 Saya pikir ini adalah sesuatu yang harus dipikirkan. Seperti berdiri, saya berharap pilihan desain ini menjadi subyek dari banyak posting blog berjudul sesuatu yang serupa juga "ES7 Dekorator Perangkap".

@Tharaxis , saya setuju dengan poin pertama Anda. Saya tidak berpikir proposal ES7 harus mencegah kami merancang sesuatu dengan baik, dan desain kami memang merupakan salah satu pendahulu ES7.

Adapun argumen "dekorator bukan fungsi", kalau tidak salah, kita tidak membahas dekorator itu sendiri, kita membahas pabrik dekorator. Dan terlepas dari perbedaan antara dekorator dan fungsi, saya pikir dekorator _factories_ sebenarnya hanya fungsi. Dan sepertinya Anda meminta kompiler untuk secara otomatis membuat panggilan ke pabrik dekorator, yang merupakan fungsi biasa. Jika itu terjadi, tidak akan mungkin bagi programmer untuk membedakan antara pabrik dekorator dan dekorator.

Juga, hal yang menyenangkan tentang memperlakukan dekorator sebagai fungsi adalah bahwa konsumen dapat menerapkannya sebagai dekorator atau hanya dengan menyebutnya sesuai keinginan mereka.

@JsonFreeman argumen berkisar pada situasi saat ini di mana ada dua cara untuk menggambarkan dan memanggil dekorator, satu melalui fungsi pabrik, dan kemudian satu sebagai fungsi "mentah" (yang dalam kasus pabrik adalah hasil dari panggilan pabrik ), dan pertanyaannya lebih tentang "bukankah seharusnya hanya ada satu cara, dan pabrik harus seperti itu".

Yang saya tanyakan adalah ya, bisakah kita tidak hanya meminta kompiler mengubah @F menjadi setara dengan panggilan @F() dan meminta pemeriksaan tipe memerlukan daftar argumen parameter 0...n saat menggunakan sintaks tidak terkurung. Mungkin Anda bisa menguraikan apa yang dimaksud dengan "...tidak akan ada cara bagi programmer untuk membedakan antara pabrik dekorator dan dekorator...", karena menurut saya sangat mudah untuk membedakannya. Dekorator selalu respon dari pabrik, dan nama pabrik adalah nama dekorator... tidak terlalu sulit, atau saya salah paham?

Adapun poin terakhir Anda tentang mengizinkan konsumen untuk hanya menerapkan dekorator, jika dijelaskan dengan baik bahwa semua dekorator menggunakan pabrik, cukup mudah untuk memanggil dekorator sendiri, Anda cukup melakukan <decorator name>(<argument list>)(target, name) dibandingkan dengan <decorator name>(target, name) sebagai contoh. Perlu diingat bahwa mengamanatkan penggunaan pabrik berarti contoh pertama akan selalu berfungsi, sementara tidak mengamanatkannya akan mengakibatkan contoh terakhir terkadang tidak berfungsi, dan sepenuhnya tergantung pada bagaimana dekorator diterapkan - sakit kepala hanya menunggu untuk terjadi.

Saya merasa perlu untuk menunjukkan, saya tidak punya masalah dengan dekorator menggunakan fungsi, masalah saya adalah bahwa memiliki dua cara untuk menggambarkan hal yang sama mengarah ke masalah konsistensi. Terutama ketika kedua cara itu juga berarti metode doa Anda harus berbeda. Ini adalah perbedaan yang menghalangi segalanya mulai dari refactoring hingga konsistensi bahasa.

Masalah refactoring yang saya jelaskan beberapa posting kembali seharusnya sudah lebih dari cukup alasan mengapa metode saat ini perlu diperiksa.

Hai semua, hanya nilai 1,5 sen terakhir dari pengguna biasa sejalan dengan apa yang dikatakan @Tharaxis .

Saya akan sangat senang dengan proposal saat ini jika:
a) alam semesta mengamanatkannya.
b) dekorator akan kehilangan kemampuan penting jika keadaannya berbeda.

Yang kemudian tentu saja merupakan penilaian nilai, yang jawabannya akan tergantung pada tingkat tertentu pada jenis pengembang Anda (yaitu pengguna umum / pengguna ahli dll). Saya berada di kategori sebelumnya dan umumnya tersebar tipis di berbagai bahasa dan kerangka kerja. Jadi bagi saya 'kemampuan penting' tidak akan menyertakan fleksibilitas untuk menulis dekorator dengan 2 cara berbeda. Contoh dari semua pengorbanan akan sangat bagus jika ada.

Idealnya akan sangat bagus jika @F dan @F() bisa konsisten terlepas dari bagaimana dekorator diterapkan, tetapi jika tidak, saya lebih suka dibatasi untuk menggunakan pabrik saat menulis dekorator daripada harus menghindari garu di rumput setiap kali saya menggunakannya.

Terima kasih & semangat

Sepertinya permintaan ini bergantung pada gagasan bahwa pabrik dekorator adalah cara kanonik untuk menggunakan dekorator, tetapi saya tidak melihat bagaimana ini memungkinkan pengguna untuk mendefinisikan dan menggunakan dekorator mentah. Jika saya mendefinisikan dekorator F , dan aplikasi @F diperlakukan sebagai @F() , maka hasil pemanggilan F digunakan sebagai dekorator, bukan F itu sendiri. Apakah Anda menyarankan kami memberikan kesalahan di suatu tempat jika seseorang mencoba menerapkan dekorator mentah alih-alih pabrik dekorator?

Ide ini terasa seperti membalikkan komposisi alami dekorator dan pabrik dekorator. Dekorator pasti merasa seperti konstruksi primitif di sini, dengan pabrik dekorator menjadi lapisan abstraksi yang dibangun di atas dekorator. Mereka hanya sebuah pola, tidak lebih. Jika bukan pabrik dekorator menjadi hal kanonik, primitif, maka orang akan mendefinisikan sekelompok pabrik dekorator, yang tidak mengambil argumen dan mengembalikan dekorator datar. Ini akan mulai terasa sangat konyol, dan itu akan membalikkan intuisi alami dari apa yang dianggap dasar dan apa yang dianggap lebih kompleks.

Satu hal yang sangat saya waspadai dengan dekorator adalah kelebihan sihir. Saya pribadi merasa gugup ketika saya tidak mengerti apa yang dilakukan kode tersebut, dan jika kompiler diam-diam menambahkan permintaan tambahan yang tidak ditulis oleh programmer, bagi saya itu terasa seperti terlalu banyak voodoo.

Hai @JsonFreeman ,

Seperti yang saya sebutkan preferensi saya akan selalu untuk keburukan berada dengan penulis dekorator daripada pengguna. Namun, saya setuju bahwa banyak pabrik tidak ada yang jelek. Bisakah dekorator digunakan untuk memperbaiki ini? Misalnya

// wraps rawDecoratorMethod in a no-arg factory method.
<strong i="8">@Decorator</strong>
function rawDecoroatorMethod(target, name, descriptor) {...}
// looks like this one would be a no-op... so that feels not quite right unless there's other advantages.
<strong i="11">@DecoratorFactory</strong>
function decoroatorFactoryMethod(someArg) {...}

Bagaimanapun, jika pendekatan semacam itu dapat dianggap masuk akal, itu memiliki keuntungan bahwa anotasi mendokumentasikan tujuan fungsi. yaitu menghiasi.

Bersulang

Saus yang enak, dekorator untuk membantu mendefinisikan dekorator, kasus Typeception yang serius.

@JsonFreeman Saya tidak yakin memiliki fungsi zero-param tentu lebih jelek daripada memiliki banyak fungsi (target, nama) sebagai gantinya. Jika ada setidaknya fungsi zero-param memberikan tingkat spesifisitas/eksplisititas yang tidak dimiliki metode lain (karena parameter tidak pernah cocok dengan permintaan dalam kasus terakhir), dan di atas itu menyediakan satu target untuk didokumentasikan sebagai gantinya tingkat inkonsistensi yang tidak perlu. Saya juga melihat keengganan untuk menempuh satu rute karena kompleksitas "mungkin" yang dirasakan, tetapi saya akan mengatakan mengingat kompleksitas "jelas" yang sangat nyata yang diterapkan oleh implementasi saat ini di sisi konsumsi, orang harus lebih banyak melakukan kesalahan di sisi dari yang jelas daripada yang mungkin.

Opsi lainnya adalah mengamanatkan bahwa dekorator yang disebut sebagai @F dapat mencocokkan pola untuk ClassDecorator, MethodDecorator, PropertyDecorator atau ParameterDecorator, ATAU fungsi pabrik 0..n arg yang mengembalikan ClassDecorator, MethodDecorator, PropertyDecorator atau ParameterDecorator. Namun saya akan merasa bahwa implementasi itu akan menyebabkan kesalahan lain (bagaimana jika Anda memiliki dua fungsi yang saling bertentangan, mana yang akan dianggap paling cocok?) dan hanya akan menambah kompleksitas yang tidak semestinya dalam kompiler. Cukup dengan mengubah panggilan @F menjadi @F() akan menjadi solusi yang lebih sederhana dan akan menyelesaikan berbagai masalah yang disebutkan.

Maaf, untuk memperjelas, saya tidak mengklaim bahwa solusi Anda rumit. Maksud saya, secara otomatis memanggil dekorator sebelum menerapkannya buram. Doa yang dimasukkan tidak terlihat oleh pengguna, dan saya merasa banyak pengguna tidak akan mengharapkannya.

Saya pikir cara berdirinya saat ini juga tidak rumit. Seperti yang Anda tunjukkan, ini memungkinkan penulis perpustakaan untuk tidak jelas atau plin-plan tentang apakah fungsi mereka dimaksudkan untuk diterapkan sebagai dekorator. Bahwa saya akan memberikan Anda. Tetapi perpustakaan yang baik akan memperjelasnya.

Dalam skema yang Anda sarankan, di mana Anda melakukan pemanggilan secara otomatis, apa yang terjadi ketika Anda menggunakan ekspresi dekorator arbitrer alih-alih hanya pengidentifikasi? Apakah itu juga dipanggil?

Saya setuju, bahwa kecuali jika didokumentasikan sebaliknya, permintaan implisit kemungkinan akan mengejutkan, tetapi hanya untuk mereka yang belum menggunakan konsep seperti atribut C# dan sejenisnya.

Bisakah Anda menguraikan apa yang Anda maksud dengan ekspresi dekorator sewenang-wenang?

Saus yang enak, dekorator untuk membantu mendefinisikan dekorator, kasus Typeception yang serius.

Panggilan yang adil. Melayani saya tepat untuk komentar yang dipikirkan dengan buruk di sore hari akhir pekan. Pelajaran yang dipelajari. Internet.undo().

Maksud saya adalah jika ternyata sintaks situs panggilan yang konsisten mengamanatkan penggunaan pabrik maka saya lebih dari senang dengan itu. Saya pasti akan menulis dekorator untuk melepas pelat ketel. Sekali lagi saya lebih suka sedikit rasa sakit saat menulis dekorator daripada rasa sakit yang berulang menggunakannya (walaupun berpotensi menimbulkan rasa sakit pada saat ini). Orang lain akan tidak setuju.

Bukankah ada juga masalah dengan peningkatan API? Dekorator yang dibuat tanpa pabrik tidak dapat menambahkan parameter opsional di lain waktu, oleh karena itu saya memprediksi @F dan @F2() di masa depan saya.

Saya juga tidak melihat bahwa Anda akan mendapatkan skenario ini saat menggunakan f dan f() , mereka adalah kasus penggunaan yang berbeda di sisi konsumsi. Dalam kasus dekorator saya selalu menerapkan/memanggil dekorator pada target saat itu juga, dan selalu ada pemanggilan metode yang terjadi di belakang layar.

Tetapi inti dari ini bagi saya adalah masalah kegunaan, ketika saya menerapkan dekorator saya tidak ingin harus google untuk mencari tahu bagaimana penulis menerapkannya - saya tertarik pada perilaku, bukan kemasannya.

Bersulang

Hanya catatan terakhir untuk meringkas dan kemudian saya akan diam. Singkatnya, ini benar-benar hanya masalah desain interaksi bagi saya. Saya sangat ingin melihat dekorator dirancang dari luar ke dalam dan bukan sebaliknya.

Sebagai orang UI/UX, saya cukup sering melihat ini. Saya telah bekerja dengan pengembang berbakat yang telah menyarankan solusi UI yang akan merugikan pengguna (satu contohnya adalah dua tombol simpan dalam satu kasus untuk menyelesaikan kompleksitas transaksi - lagi-lagi pria yang cerdas dan manusia yang baik). Saya hanya berpikir ketika Anda tenggelam dalam logika detail implementasi yang kompleks, mungkin sulit untuk melupakan apa yang Anda ketahui dan melihatnya melalui mata rata-rata pengguna.

Sekarang jika rata-rata saya benar-benar salah, atau jika kompleksitas mengamanatkan desain saat ini maka semuanya baik-baik saja, saya hanya perlu mengaktifkan otak dan belajar.

Bersulang

Jika dekorator Anda bukan pengidentifikasi, tetapi ekspresi lain, apakah Anda akan secara otomatis memanggilnya? Misalnya, katakanlah itu adalah dekorator. OR-ed dengan ekspresi fungsi fallback. Sesuatu seperti:

@(F || function (target) { // default decorator behavior })
class C { }

Apakah Anda kemudian secara otomatis memanggil ini? Itu akan memberi Anda hasil yang salah karena Anda akhirnya memanggil dekorator default sebelum diterapkan:

(F || function (target) { // default decorator behavior })()

Ini sepertinya tidak benar.

@JsonFreeman , apakah sintaks dekorator memungkinkan ekspresi sewenang-wenang seperti itu? Saya tidak 100% yakin mengizinkan pengembang sebanyak itu untuk menggantung diri adalah ide yang bagus, tapi itu hanya saya (murni karena saya tidak melihat ekspresi sewenang-wenang seperti itu menyelesaikan masalah penggunaan kembali/boilerplate yang ingin diselesaikan oleh dekorator dan sebagai gantinya hanya berfungsi untuk membuat kode terlihat jelek dan bahkan lebih sulit untuk diikuti).

Yang mengatakan, saya kira satu-satunya cara itu akan berhasil adalah jika ekspresi arbitrer itu sendiri mengevaluasi ke sintaks pabrik yang sama, jadi:

@(F || () => function(target) { /* default decorator behaviour */ })
class C { }

Saya setuju itu menyebabkan Anda harus meletakkan beberapa bit lagi di sekitar dekorator arbitrer Anda, tetapi saya pikir seseorang memiliki masalah yang lebih besar daripada penambahan () => jika Anda menggunakan ekspresi arbitrer sebagai dekorator.

CATATAN: Saya jelas tidak bermaksud bahwa sintaks lambda akan menjadi satu-satunya cara untuk mendeklarasikannya, tetapi () => sedikit lebih bagus daripada function() { return function(target) { /*...*/ } } .

Benar-benar maaf mengganggu debat sintaksis pemanggil dekorator ini, tetapi adakah yang bisa secara resmi mengklarifikasi urutan pemanggilan ekspresi dekorator? Terutama, di sepanjang garis tipe target dekorator, posisi anggota target di sumber asli dan urutan dekorator pada satu target.

@billccn Dekorator diterapkan dari bawah ke atas. Jadi dalam kode sumber asli jika Anda punya

class C {
    <strong i="7">@F</strong>
    <strong i="8">@G</strong>
    method() { }
}

Ini pertama-tama akan menerapkan G ke metode, dan kemudian menerapkan F ke hasilnya. Apakah ini yang Anda tanyakan?

Bagaimana untuk ini:

<strong i="6">@A</strong>
class Clazz {
    <strong i="7">@B</strong>
    prop = 1;

    <strong i="8">@C</strong>
    method() {}

    <strong i="9">@D</strong>
    get prop() {return 1;}

    <strong i="10">@E</strong>
    method2() {}

    <strong i="11">@F</strong>
    prop2 = 1;
}

mereka mengikuti urutan ruang lingkup, jadi semua properti/metode terlebih dahulu, dalam urutan deklarasi, lalu kelas satu. yaitu B, C, D, E, F, A.

Anda dapat melihat kode yang dihasilkan di sini .

Tampaknya saat ini tidak mungkin untuk mendekorasi properti parameter. Bisakah mereka didukung?

Properti parameter adalah hal seperti constructor(private prop: Type) , di mana properti (bidang) dan parameter dideklarasikan bersama. Masalahnya adalah keduanya dapat didekorasi, sehingga beberapa sintaks imajinatif mungkin harus ditemukan.

Pertanyaan: Dapatkah dekorator digunakan untuk mengubah perilaku metode objek biasa, seperti...

var isCreatorUser = () => {  /* code that verifies if user is the creator */ },
    isAdminUser = () => { /* code that verifies if user is admin */ },

var routeConfig = {
    get() {},
    <strong i="7">@isCreatorUser</strong> patch() {},
    <strong i="8">@isAdminUser</strong> <strong i="9">@isCreatorUser</strong> delete() {}
};

... dan jika tidak, mengapa? Ini akan sangat berguna.

Belum, tapi kami sedang mempertimbangkannya. @rbuckton mungkin memiliki lebih banyak detail.

Bolehkah saya bertanya mengapa dekorator tidak dapat mengubah jenis hasil yang dihias dari jenis yang dihias?

Misalnya, MethodDecorator dapat diusulkan sebagai alternatif seperti di bawah ini:

declare type MethodDecorator = <T, R>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<R> | void;

Jadi dekorator bisa lebih fleksibel untuk digunakan dan bekerja seperti makro. Jenis kelas/bidang yang didekorasi dapat diperbarui sesuai dengan jenis pengembalian penghias, sehingga keamanan jenis tetap terjaga.

Saya tahu bahwa https://github.com/jonathandturner/brainstorming/blob/master/README.md#c4 -defining-a-decorator telah menyatakan jenis yang dikembalikan harus sama. Tapi type validity bukan argumen yang valid di sini, IMHO. Pertama, dekorator dalam JavaScript dapat mengubah tipe kelas/bidang, sehingga tidak ada masalah kompatibilitas antara TS dan JS. Kedua, dekorator diterapkan secara statis, kompiler TS dapat memberi alasan tentang jenis bidang asli dan jenis bidang yang didekorasi di situs yang ditentukan.

@HeringtonDarkholme saya akan mengatakan ini perlu dilacak dalam saran yang berbeda. Alasan utamanya adalah cara kompiler beralasan tentang tipe adalah melalui deklarasi. sekali jenis dinyatakan tidak bisa berubah. menambahkan mutator tipe dalam campuran berarti kita perlu menyelesaikan ini karena kita sedang menyelesaikan deklarasi yang bisa berbulu.

@mhegazy jadi, bisakah saya memahami ini sebagai kompromi untuk kemudahan implementasi, daripada desain yang disengaja?

Menurut proposal ini , dekorator mengembalikan kemampuan untuk menjalankan kode pada waktu desain, sambil mempertahankan sintaks deklaratif. Jadi kode berikut akan menjadi
valid di JavaScript masa depan, tetapi tidak valid di TypeScript hari ini (namun ini mungkin diterima oleh TS suatu hari nanti, kan?).

function SafeCtor(target) {
  var safe = function(...args) {
    var instance = Object.create(target.prototype)
    target.call(instance, ...args)
    return instance
  }
  safe.prototype = target.prototype
  return safe
}

<strong i="10">@SafeCtor</strong>
class Snake {
  constructor(name) {
    this.name = name
  } 
}

var snake = Snake('python')
alert(snake instanceof Snake)

Saya tahu peluang untuk mendukung fitur ini kecil. Tapi saya ingin memastikan ini bukan cerita yang sama seperti structural vs nominal mengetik.

Pemeriksaan saat ini adalah Anda harus mengembalikan sesuatu dari dekorator Anda yang dapat dialihkan ke target. bagian yang hilang adalah kami tidak menangkap tambahan apa pun pada jenisnya. Saya tidak berpikir kami memiliki ide tentang bagaimana melakukan itu, tetapi kami juga belum benar-benar memikirkannya. jadi saya pikir itu adalah saran yang adil, tetapi biaya untuk menerapkannya mungkin sangat tinggi.

Idealnya, saya pikir tipe yang dikembalikan oleh dekorator harus identik dengan target. Tidak ada yang tahu apakah Anda akan menggunakan jenis dekorasi di sumber atau posisi target dalam tugas.

Meskipun saya kira kita harus menggabungkan tipe pengembalian dekorator dan target, seperti mixin.

Hanya beberapa ide fungsionalitas tambahan. Karena keluaran kompiler TypeScript adalah JavaScript, ada beberapa bahasa serupa untuk Java, seperti Xtend

Anda dapat mempelajari beberapa ide menarik tentang proyek ini. Cari Anotasi Aktif "Anotasi aktif memungkinkan pengembang untuk berpartisipasi dalam proses terjemahan kode sumber Xtend ke kode Java melalui perpustakaan"

Mengontrol output TypeScript melalui dekorator akan menjadi fitur yang sangat bagus!

Dekorator untuk antarmuka, harus dimungkinkan.

@shumy Masalahnya adalah antarmuka tidak ada saat runtime dengan cara apa pun, dan dekorator berjalan murni saat runtime.

Apakah ada alasan untuk memperlakukan dekorator properti secara berbeda dari dekorator metode sehubungan dengan nilai pengembalian? (Babel tidak).

Maksud saya adalah, jika saya ingin mendefinisikan fungsionalitas untuk properti melalui dekorator, saya harus melakukan ini:

function decorator(proto, name) {
    Object.defineProperty(proto, name, { value: 42 });
}

class Foo {
    <strong i="7">@decorator</strong>
    a: number;
}

Sedangkan Babel mengharuskan deskriptor dikembalikan:

function decorator(proto, name) {
    return { value: 42 };
}

class Foo {
    <strong i="11">@decorator</strong>
    a;
}

Hal ini mempersulit penulisan dekorator di TypeScript yang merupakan bagian dari library yang akan digunakan dari Babel.

Saya akan mengusulkan agar dekorator properti diperlakukan secara identik dengan dekorator metode, dan nilai pengembalian dekorator harus diterapkan melalui Object.defineProperty . Ini juga akan memungkinkan beberapa dekorator pada satu properti, seperti metode.

Solusi untuk saat ini (untuk kompatibilitas Babel) adalah mengembalikan deskriptor dari dekorator selain mengatur properti, tetapi itu tampaknya tidak perlu boros:

function decorator(proto, name) {
    var d = { value: 42 };
    Object.defineProperty(proto, name, d);
    return d;
}

@mhegazy apakah Anda memiliki wawasan tentang komentar saya di atas?

@sccolbert Dalam TypeScript kami memilih untuk melarang penggunaan deskriptor properti untuk dekorator pada properti data, karena dapat menyebabkan masalah saat runtime karena fakta bahwa "nilai" apa pun yang ditentukan oleh deskriptor akan ditetapkan pada prototipe dan bukan pada instance . Meskipun contoh Anda di atas umumnya tidak menjadi masalah, pertimbangkan hal berikut:

function decorator(proto, name) {
  return { value: new Point(0, 0); }
}

class Foo {
  <strong i="7">@decorator</strong>
  p: Point;

  setX(x) { this.p.x = 1; }
}

let a = new Foo();
let b = new Foo();
console.log(a.p.x); // 0
b.setX(10);
console.log(a.p.x); // 10 (!)

Ada proposal untuk versi ES yang akan datang untuk mendukung properti "penginisialisasi" pada deskriptor, yang akan dievaluasi selama konstruktor. Itu akan memberi Anda kemampuan untuk mengontrol apakah nilai ditetapkan pada prototipe atau dialokasikan per instance.

Untuk saat ini Anda dapat mengatasi batasan ini dengan memanggil Object.defineProperty secara langsung, sesuai contoh di komentar Anda. Kami akan terus menyelidiki apakah akan melonggarkan pembatasan ini di masa mendatang.

@rbuckton terima kasih! Apakah kalian dalam pembicaraan dengan Babel untuk bertemu pada semantik yang sama? Saya pikir itu hal yang paling penting.

Mengapa berguna untuk menggunakan dekorator untuk menentukan nilai untuk contoh tertentu? Bukankah itu untuk penginisialisasi properti?

Kasus penggunaan saya lebih rumit daripada contohnya. Saya sebenarnya menggunakan dekorator untuk mendefinisikan pengambil yang mengembalikan objek yang terikat ke this konteks properti, sehingga metode pada objek tersebut memiliki akses ke instance yang didefinisikan.

Anda dapat menganggap ini sebagai meniru protokol deskriptor dengan Python, di mana mengakses metode bar didefinisikan pada kelas Foo melalui instance foo (yaitu foo.bar ) memanggil __get__ metode fungsi yang mengembalikan BoundMethod . Ketika objek itu dipanggil, fungsi yang mendasari dipanggil dengan self sebagai argumen pertama, yang dalam hal ini adalah foo . Javascript tidak memiliki konsep ini, itulah sebabnya kita harus melewati thisArg dan memanggil function.bind semua tempat.

Untuk kasus saya, saya tidak mendefinisikan metode, tetapi sinyal tipe-aman. Ini dia dekoratornya:
https://github.com/phosphorjs/phosphor-signaling/blob/1.0.1/src/index.ts#L144

Ketika properti diakses, ia mengembalikan implementasi ISignal yang terikat dengan konteks this pemilik. Ini memungkinkan sinyal untuk merujuk kembali ke instance yang didefinisikan:
https://github.com/phosphorjs/phosphor-signaling/blob/1.0.1/src/index.ts#L263

Jadi pada dasarnya, saya menggunakan dekorator sebagai jalan pintas untuk persamaan verbose ini:

class Foo {
  valueChanged: ISignal<number>;
}

defineSignal(Foo.prototype, 'valueChanged');

@rbuckton

Dekorator tidak diperbolehkan saat menargetkan ES3

Mengapa? Saya tidak dapat melihat apa pun yang akan mencegah penggunaan __decorate di ES3.

Ini menggunakan deskriptor properti, yang tidak tersedia di ES3
Le 4 september 2015 14:03, "Koloto" [email protected] a écrit :

@rbuckton https://github.com/rbuckton

Dekorator tidak diperbolehkan saat menargetkan ES3

Mengapa? Saya tidak dapat melihat apa pun yang akan mencegah penggunaan __decorate di ES3.


Balas email ini secara langsung atau lihat di GitHub
https://github.com/Microsoft/TypeScript/issues/2249#issuecomment -137717517
.

@sccolbert Anda mungkin melakukannya lebih baik dengan proxy ES6 daripada dekorator properti.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Peramban @DavidSouther belum mendukung Proksi :(

@cybrown Ya, ini menggunakan deskriptor properti untuk metode dan

Dan deskriptor properti palsu dapat digunakan untuk metode saat menargetkan ES3. Sesuatu seperti { writable: true, enumerable: true, configurable: true } . Jadi saya tidak melihat alasan untuk tidak mendukung ES3.

@sccolbert saya mengerti. Itu masuk akal. Kebetulan, TypeScript sedang mengerjakan pengetikan _this_ yang ditingkatkan untuk fungsi dan metode. Saya ingin tahu apakah itu akan membantu di sini. Meskipun saya kira mengetik bukan masalah bagi Anda, ini adalah semantik runtime.

@JsonFreeman Pengetikan _this_ yang ditingkatkan terdengar menarik untuk beberapa kasus penggunaan saya yang lain. Apakah Anda memiliki info lebih lanjut tentang itu?

Saya pikir diskusi yang paling berkembang tentang pengetikan _this_ ada di #3694.

Bersulang!

kesalahan TS1207: Dekorator tidak dapat diterapkan ke beberapa pengakses get/set dengan nama yang sama.

<strong i="6">@get</strong>
public get myValue():any{...}

<strong i="7">@set</strong>
public set myValue(value:any){...}

kode di atas tidak diperbolehkan bahkan lebih masuk akal dibandingkan dengan

<strong i="11">@get</strong>
<strong i="12">@set</strong>
public get myValue():any{...}

public set myValue(value:any){...}

Getter dan setter didefinisikan dalam satu panggilan ke Obect.defineProperty. Ini agak kekhasan js, deklarasi set dan get meskipun terpisah, sebenarnya adalah deklarasi properti yang sama. Pemeriksaan kesalahan dalam kompiler adalah untuk memperingatkan pengguna ketika memikirkannya secara terpisah; dekorator diterapkan hanya sekali ke deskriptor properti.

hanya ingin tahu karena kompiler dapat merasakan get dan set dengan nama yang sama dan digabungkan menjadi satu Object.defineProperty, mengapa tidak juga menggabungkan dekorator?
atau mungkin flag opsi untuk memberi tahu kompiler untuk menggabungkannya, dan meninggalkan pesan peringatan alih-alih melempar kesalahan.

Terima kasih

@TakoLittle : Alasan kami tidak melakukan ini hari ini sebagian berasal dari bagaimana dekorator disusun. Dekorator mengikuti prinsip yang sama dengan komposisi fungsi Matematika, di mana (_f_ _g_)(_x_) disusun sebagai _f_(_g_(_x_)). Dalam pengertian yang sama, dapat dianggap bahwa:

<strong i="7">@F</strong>
<strong i="8">@G</strong>
class X {}

Apakah kira-kira:

F(G(X))

Komposisi dekorator rusak saat Anda mendekorasi getter dan setter:

class C {
  <strong i="15">@F</strong>
  set X(value) {}

  <strong i="16">@G</strong>
  get X() {}
}

Bagaimana cara F dan G menulis di sini? Apakah ini murni berdasarkan pesanan dokumen (yaitu F(G(X)) )? Apakah setiap set dekorator untuk pengambil dan penyetel terpisah, dan kemudian dieksekusi dalam urutan dokumen (yaitu G(F(X)) )? Apakah get dan set menyiratkan pemesanan tertentu (yaitu get selalu sebelum set atau sebaliknya)? Sampai kami 100% yakin pendekatan paling konsisten yang tidak mengejutkan pengguna, atau memiliki pendekatan yang terdokumentasi dengan baik yang merupakan bagian dari proposal dekorator dengan setidaknya tahap 2 atau penerimaan yang lebih baik dalam ECMA-262, kami merasa sebaiknya lebih membatasi dan error di sini karena memungkinkan kita untuk melonggarkan pembatasan itu di kemudian hari tanpa memperkenalkan perubahan yang dapat dengan mudah luput dari perhatian dan mungkin menghasilkan perilaku yang tidak terduga saat runtime.

@rbuckton terima kasih banyak atas penjelasan detailnya
Tim TS kerja bagus!! ^^d

Di mana dokumentasi untuk ini? dan peduli untuk menautkan komitmen implementasi?

Terima kasih.

@mhegazy Apa status implementasi versi terbaru dari spesifikasi. Saya mengerti ada beberapa perubahan di sana.

Masalah ini melacak versi asli proposal. karena ini selesai kami menutup masalah ini. untuk setiap pembaruan spesifikasi, kami akan mencatat masalah baru dan menguraikan semua perubahan yang melanggar. Saya tidak berpikir proposal itu ada di tempat sekarang untuk siap kita lompati. Kami bekerja sama dengan @wycats untuk proposal baru.

@mhegazy Terima kasih atas pembaruannya. Saya ingin tetap mendapat informasi. Saat Anda membuat masalah baru untuk pembaruan spesifikasi, harap tautkan di sini agar saya dapat diberi tahu dan mengikuti. Komunitas Aurelia banyak menggunakan dekorator dan kami ingin menyinkronkan dengan TypeScript dan Babel pada pembaruan. Sekali lagi, terima kasih atas kerja luar biasa yang dilakukan tim TS!

Fungsi dekorasi sangat dibutuhkan tentunya.
Apakah ada juga rencana untuk mendekorasi objek lain dalam kode?

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

manekinekko picture manekinekko  ·  3Komentar

weswigham picture weswigham  ·  3Komentar

Roam-Cooper picture Roam-Cooper  ·  3Komentar

Antony-Jones picture Antony-Jones  ·  3Komentar

CyrusNajmabadi picture CyrusNajmabadi  ·  3Komentar