Typescript: مصممون

تم إنشاؤها على ٧ مارس ٢٠١٥  ·  139تعليقات  ·  مصدر: microsoft/TypeScript

اقتراح ES7

يمكن العثور على اقتراح ES7 لمصممي الديكور هنا: https://github.com/wycats/javascript-decorators
يعتبر اقتراح ES7 بمثابة أساس لهذا الاقتراح. فيما يلي ملاحظات حول كيفية نظام الكتابة

أهداف الديكور:

مُنشئ فئة

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

desugars إلى:

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

أساليب

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

desugars إلى:

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;
})();

طريقة ثابتة

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

desugars إلى:

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

الخصائص

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

desugars إلى:

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

الأسلوب / المعامل الرسمي للموصل

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

desugars إلى:

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;
})();

حيث يتم تعريف __الديكور على أنه:

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;
};

توقيعات المصمم:

يجب أن يكون المصمم الصالح:

  1. قابل للتخصيص لأحد أنواع الديكور (ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator) كما هو موضح أدناه.
  2. قم بإرجاع قيمة (في حالة مصممي الفئة ومُصمم الطريقة) يمكن تخصيصها للقيمة المزخرفة.
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;

ملحوظات:

  • لا يُسمح بتزيين إعلان الوظيفة لأنه سيمنع رفع الوظيفة إلى أعلى النطاق ، وهو تغيير مهم في دلالات الألفاظ.
  • لا يتم دعم تعبيرات وظائف التزيين ووظائف الأسهم. يمكن الحصول على نفس التأثير من خلال تطبيق وظيفة الزخرفة مثل var x = dec(function () { });
  • تزيين المعلمات الرسمية للوظيفة ليس حاليًا جزءًا من اقتراح ES7.
  • لا يُسمح بالديكور عند استهداف ES3
Committed ES Next Fixed Suggestion

التعليق الأكثر فائدة

زخرفة الوظيفة تحتاج بالطبع.
هل توجد أيضًا خطط لتزيين أشياء أخرى في الكود؟

ال 139 كومينتر

معذرةً مما أفهمه من المواصفات ، لن نتمكن من القيام به:

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

هل انا على حق ؟

كيف يعمل نوع التسلسل مع بقية الوسائط؟

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

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

يبدو استخدام أدوات الزخرفة بسيطًا بما يكفي ، لكنني وجدت الأقسام المتعلقة بالتصريح بأنها مربكة. يقول C.4 أن المصممين يحتاجون إلى التعليق التوضيحي بـ @decorator ، لكن لا أحد الأمثلة يوضح حدوث ذلك بالفعل.

هل يقصد بمصانع الديكور أن تكون فئات تنفذ الواجهات الموجودة في B؟

ما هي القاعدة لتنقيح تفسير CoverMemberExpressionSquareBracketsAndComputedPropertyName؟

لقد لاحظت أن العديد من الكتابات تحتوي على Function | Object في نقاط مختلفة ، ولكن ستتحول إلى كائن في وقت التحقق من النوع. ما سبب وجود الوظيفة هناك؟

أنا لست مجنونًا بشروط DecoratorFunction vs DecoratorFactory. أفضل اتباع مصطلحات المولدات ، التي تحتوي على وظيفة المولدات والمولدات. باستخدام هذا المخطط ، نعيد تسمية وظيفة Decorator إلى Decorator ، و DecoratorFactory إلى DecoratorFunction.

بالنسبة للصادرات المزخرفة ، ما هو [lookahead ≠ @] ؟ هل يمكن أن يبدأ إعلان Hoistable و ClassDecisions فعليًا بـ @ ؟

هذه صورة مزدوجة رقم 1557

إنها ليست خدعة حقًا ، لأن # 1557 كان لتصميم مختلف. هذا الموضوع يتعلق بتصميم الديكور الجاري تنفيذه الآن.

غلطتي.

بالنسبة إلى المصمم على التعبير الوظيفي ، لا يمكننا فعل شيء مثل:

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

تحول إلى:

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

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

يزعج البعض بعض الشيء في تصحيح كل وظيفة مثل:

const myFunc = function () {}

لقد خسرت الرفع ، و function.name

تمت إضافة التنفيذ في PR # 2399

التحديثات: تم تحديث الاقتراح وإضافة رابط إلى wycats ES7 JavaScript decorators.

حزينًا لأنه أصبح شيئًا طبقيًا فقط ...
أيضا ماذا عن الديكور المحيط هل خرجوا من النطاق؟

fdecampredon مع

تضمين التغريدة إذا أدخلت _t في أعلى الملف؟

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)
}

أيضًا حتى إذا كان اقتراحي يحتوي على الكثير من المشكلات ، أود بجدية أن أكون قادرًا على استخدام الزينة في الوظيفة (حتى لو كان علي استخدام وظيفة مخصصة متغيرة) وفقد الرفع.
تبدو مثل هذه الحالة بمثابة حالة استخدام جيدة للديكور لكل من الوظيفة والفئة (خاصةً إلى جانب الديكورات المحيطة إذا كانت لا تزال في النطاق)

fdecampredon هذا لا يعمل للحالة العامة ، حيث أن المصممين هم تعبيرات بحد ذاتها. على سبيل المثال

myFunc();  // assumes function declaration is hoisted

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

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

إذا قمت برفع إعلان الوظيفة وتطبيق الديكور ، فإنك تكسر المصمم. إذا قمت فقط برفع إعلان الوظيفة ، ولكن ليس تطبيق الديكور ، يمكنك مشاهدة الوظيفة في حالة غير مزخرفة. لا توجد حلول جذابة هنا.

هذه هي نفس المشكلة كما هو الحال مع شرط تمديد إعلان الفئة ، والذي يعد تعبيرًا في ES6. لم تكن النتيجة رفع إعلان الفئة ، فقط الرمز (أقرب إلى إعلان var ، ولكن ليس الإعلانات الوظيفية)

لم يفكر Oups في ذلك ، شكرًا لكmhegazy.
ومع ذلك ، فإن سبب تخلي جزء الوظيفة تمامًا عن اقتراح jonathandturner الأصلي كان له القاعدة:

decorated function declarations cannot be hoisted to the containing scope

من المؤكد أن فقدان الرفع يمثل عيبًا ، لكنني أجد أنه من القابل للتلف تحويله إلى ميزة فئة فقط عندما يكون لها حالة استخدام لبناء آخر.

دعونا نرى ما يبدو أن مجموعة القيود المطلوبة تعني:

  • يجب رفع الوظيفة المزخرفة
  • يجب تزيين الوظيفة بمجرد توفرها - لذلك يجب رفع تطبيق الديكور
  • يجب تحديد مصمم الديكور قبل تطبيقه - لذلك يجب رفع تعريف المصمم نفسه (أو جميع الكيانات المشار إليها بواسطة تعبير المصمم)
  • يتم تقييم تعبير المصمم في المكان الذي يتم تطبيقه فيه معجميًا - وبالتالي لا يمكن رفع التطبيق

الحل الوحيد الذي يمكنني رؤيته لهذا هو ما يلي: بالنسبة لمصممي الوظيفة ، نسمح فقط بشيء من النموذج @identifier . لا نسمح بتعبير جهة اليسار. بالإضافة إلى ذلك ، يجب أن يكون المعرف مرجعًا مباشرًا لإعلان الوظيفة (بما في ذلك الوظيفة المزخرفة). يجب أن تنبعث جميع الزخارف الوظيفية التي تحدث في النطاق في الجزء العلوي من النطاق ، بالترتيب الذي تم تطبيقه بها.

مشكلة كسر قواعد الرفع هي أنه أمر مفاجئ. إذا كنت تكتب جافا سكريبت لفترة من الوقت ، فإنك تتوقع أن تكون إعلانات الوظائف متاحة قبل الإعلان عنها معجمًا ؛ الآن من خلال إضافة علامة نحوية بسيطة على ما يبدو (المصمم) يتم تغيير هذه الطبيعة الأساسية لإعلان الوظيفة.

بعد قولي هذا ، لا يزال اقتراح ES7 في مراحله الأولية ، لذلك أتوقع أن يتطور ويتوسع ؛ لذلك فمن المتصور أن يتضمن الاقتراح النهائي وظائف في شكل ما.

أعتقد أنه يجب رفعهم. أنا أقول إن الزخارف الوحيدة التي نسمح بها للوظائف هي الزخارف التي يتم رفعها بالتأكيد. وهي المعرفات التي تشير إلى إعلانات الوظائف.

لكن هناك مشكلة أخرى هنا. من المستحيل في الواقع رفع جميع الوظائف المزخرفة في نفس الوقت والتأكد من عدم ملاحظتها في حالتها غير المزخرفة. يمكن رؤية المشكلة مع دورة الديكور.

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

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

حتى لو تم رفع كلتا الوظيفتين ، فأي واحدة يتم تزينها أولاً؟ إذا تم تزيين dec2 أولاً ، فلن يتم تزيين dec1 نفسه بحلول الوقت الذي يتم تطبيقه فيه على dec2.

لذلك علينا الاختيار بين ما يلي:

  • لا يتم رفع الوظائف
  • يتم رفع الوظائف غير المزخرفة ، لكن تطبيقات الديكور لا يتم رفعها معهم.

على الرغم من أنني لا أحب أيًا من هذين ، إلا أنني لا أعتقد أن أي شيء آخر ممكن.

هذا هو اقتراح JS. لذلك لن يعرف المحرك ما إذا كان التعبير يشير إلى إعلان وظيفة أم لا ، مع التحليل الثابت يمكننا معرفة ذلك. اعتبر هذا:

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

dec2 = undefined;

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

قرف! جافا سكريبت لم تعد أكثر بساطة. :-)

سيكون من الأسهل تمكينه فقط في الوظيفة _expressions_:

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

لا يتم رفع تعبيرات الوظائف أو لامدا.

هل من الممكن أن يكون لديك معلمات مثل هذه في مُصمم ديكور بخط مطبوع 1.5.0-alpha؟

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

حسنًا ، فما عليك سوى إنشاء مصنع يأخذ المعلمات ويعيد وظيفة الديكور الفعلية.

على سبيل المثال ، مصمم فئة مع معلمة سلسلة:

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

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

}

تحية طيبة.

أحاول معرفة كيفية كتابة مصمم ديكور يلتقط الأنواع المعلنة في المنشئ.

إليكم بعض الكود الذي يوضح ما أحاول القيام به ، لكنه متشابك. أحتاجه للرد على إعلان المنشئ في الفئة 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;
}

أخشى أن تكون معلومات النوع خارج نطاق ميزة الديكور.
يمكنك استخدام ParameterDecorator على كل معلمة لإضافة هذا النوع من المعلومات.

الكتابة أو التنفيذ لـ ParameterDecorator ليس صحيحًا تمامًا ، من الكتابة ، الهدف هو وظيفة ، ولكن أثناء استخدام الكتابة المطبوعة ، فهي كائن النموذج الأولي.
يجب أن ألقي المعلمة الهدف من أجل الحصول على النوع الصحيح:

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

بدلا من:

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

واو - حكم معلمة الزخرفة !!!!!!!!!!!!!!! انظر هذا الريبو

إليك ناتج إجراء الاختبارات:

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

والرمز :

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)
        }
      }
    });
  });
}

لقد صنعت غلافًا حول Express (ولكن يمكن دعم أي إطار عمل للويب ، يتم تحديد واجهة محول) باستخدام واجهة برمجة تطبيقات تعتمد على الديكور: https://github.com/cybrown/web-decorators

أنا أستخدم ClassDecorator و ParameterDecorator و MethodDecorator.

cybrown لقد قمت للتو بتحديث التوقيع لـ ParameterDecorator في # 2635 ، وهو الآن في المستوى الرئيسي.

rbuckton شكرًا لك ، سأقوم بتحديث ذلك غدًا في مشروعي.

هل من الممكن أن يكون اسم المعلمة في ParameterDecorator؟
قد يكون هذا مفيدًا لأنني أعتقد أن اسم المعلمة قد يكون نصف الوقت الوسيطة الأولى لـ ParameterDecorator.
علاوة على ذلك ، قد يكون حلاً لتغيير اسم المعلمة بواسطة المصغرات.

لقد طُلب مني إنجاز هذا:

@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;
    }
  }

ولكن بدون تحديد المفاتيح في أداة الحقن ، ولكن بدلاً من ذلك ، اجعل المصممين يلتقطون وظائف فئة المُنشئ تلقائيًا مع شيء على غرار هذه الخطوط:

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

أنا أبحث عن كيفية القيام بما يصفه jonathandturner هنا

cmichaelgraham نعم الحصول على معلومات من نوع وقت التشغيل (rtti كما هو موضح في AtScript) سيكون رائعًا لهذا النوع من الاستخدام ، حتى في ميزة منفصلة تمامًا مثل الاستبطان.

cmichaelgraham انظر إلى https://github.com/Microsoft/TypeScript/pull/2589

cmichaelgraham نحن نعمل على اقتراح لـ ES7 لإضافة Metadata API التي ستعمل مع المصممين. يضيف # 2589 دعمًا تجريبيًا لهذا الاقتراح ، ولكنه يتطلب وجود polyfill منفصل لقراءة البيانات الوصفية.

rbucktoncmichaelgraham كان هناك في الأصل تصميم خاص الديكور نسخة مطبوعة على الآلة الكاتبة التي من شأنها أن نقول للمترجم لأنواع حقن في الديكور، استنادا إلى الهدف الذي زينت. أعتقد أنه كان @parameterTypes هل أنا محق في اعتقادي أنه تمت إزالة هذه الميزة لصالح واجهة برمجة التطبيقات للبيانات الوصفية الأكثر عمومية؟ إذا كان الأمر كذلك ، فسأؤيد ذلك.

هل يمكنك التحدث قليلاً عن حالة ذلك فيما يتعلق بـ TypeScript. هل هذا مخطط لإصدار 1.5؟ إذا كان الأمر كذلك ، كيف ستبدو خيارات المترجم؟ الشيء الوحيد الذي قد يكون مفيدًا هو جعل المترجم ينشئ تلقائيًا بيانات تعريف النوع لتوقيعات المُنشئ فقط.

EisenbergEffect Decorators جزء من 1.5 ، يمكنك البدء في استخدامه مع أحدث إصدار لدينا 1.5-alpha .

أما بالنسبة لدعم البيانات الفوقية. تم تغيير التصميم منذ الاقتراح الأصلي لـ @paramtypes . التصميم الجديد يستخدم اقتراح Reflect.metada. راجع # 2589 لمزيد من التفاصيل حول كيفية عملها. يحتوي أيضًا https://github.com/rbuckton/reflectDecorators

mhegazy أعرف ذلك. انظر هنا: http://blog.durandal.io/2015/04/09/aurelia-update-with-decorators-ie9-and-more/ : ابتسامة:

أنا أيضًا على دراية بمقترح البيانات الوصفية. لقد كنت أقدم ملاحظات على ذلك. أردت فقط معرفة ما إذا كانت الفكرة الأصلية @parameterTypes قد تمت إزالتها.

شكرا EisenbergEffect للمشاركة. : +1:

نعم فعلا. المشكلة الوحيدة مع @paramtypes هي أنه يجعل الانبعاث موجهًا بواسطة نظام النوع ، ويتطلب معلومات البرنامج العالمية. هذا يكسر سيناريوهات الترشيح لوحدة واحدة (انظر # 2499). كان الخيار الآخر هو وضعه على مواقع الاتصال ، مما يضيف الكثير من العمل على مستخدمي الديكور بدلاً من المؤلفين. لذلك عدنا إلى لوحة الرسم ووقفنا على منهج Reflect.metadata بدلاً من ذلك.

إذا نظرت أيضًا إلى الإصدارات السابقة من الاقتراح ، فسيتعين علينا إزالة الديكور المحيط / وقت التصميم لنفس السبب.

شكرا للتوضيح. كل هذا منطقي. أي فكرة عما إذا كان النهج القائم على انعكاس سيصل إلى 1.5؟

نعم فعلا. هو حاليا في الماجستير. يجب أن يكون متاحًا في الإصدار التالي. إنها حاليًا ميزة اشتراك باستخدام العلم التجريبي --emitDecoratorMetadata ؛ ويضيف فقط البيانات الوصفية للكيانات المزخرفة.

"يضيف فقط البيانات الوصفية للكيانات المزخرفة" هل يمكنك التوسع في هذه الفكرة؟ هل يشارك مصمم خاص؟ أم أنها تضيفها إلى أي شيء مع أي مصمم ديكور؟ بمعنى آخر ، إذا استخدم المطور مصمم Aurelia inject decorator ، فهل سيؤدي ذلك إلى تشغيل المترجم لإنشاء البيانات الوصفية؟

إذا استخدم المطور أداة تزيين الحقن من Aurelia ، فهل سيؤدي ذلك إلى تشغيل المترجم لإنشاء البيانات الوصفية؟

نعم فعلا.

ما قصدته هو:

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

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

باستخدام --emitDecoratorMetadata سيصدر المترجم بيانات وصفية من النوع (أي استدعاء reflect.metadata('desing:paramtypes', [Number, String]) ) مقابل Foo لكن _not_ Bar .

هذا سوف يعمل من أجلنا. سنقوم بإعداد الدعم لواجهة برمجة تطبيقات Reflect.metadata لإصدارنا القادم ، على الأرجح الأسبوع المقبل. شكرا على التوضيح!

فما الذي ينبعث من هذا؟

"" اللغة = جافا سكريبت
@حقن
فئة فو {
المُنشئ (أ: أ ، ب: ب) {}
}

شريط الصف {
المُنشئ (a: number، b: B) {}
}

would it be (for Foo):

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

cmichaelgraham نعم ، هذا تقريبًا ما تم إنشاؤه.

جنون رائع !!!!

استخدام gulp-typescript لبناء هذا الريبو - (عمل لطيفivogabe)

gulpfile build-ts الأمر (لاحظ الخيار 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('.'))
    ]);
});

يتحول إلى 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' }
      ]);
    });
  }
}

إلى 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;
});

من الأمور ذات الأهمية الخاصة البيانات الوصفية للنوع المنبعث حول معلمات المُنشئ:

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

لذلك من الناحية النظرية ، يمكنك تغيير وظيفة مُزخرف الحقن لحقن الفئات المناسبة دون تحديدها في الحقن ، ولكن بدلاً من ذلك تحديد الأنواع في المُنشئ :)

cmichaelgraham يمكننا بسهولة تمكين هذا اليوم دون تغيير إطار العمل. مكتبة DI من Aurelia بها خطاف container.addParameterInfoLocator . تقوم بتمريرها وظيفة يمكن أن تأخذ نوعًا وتعيد تبعياتها. بالنسبة لإصدارنا التالي (الأسبوع المقبل) ، يمكننا إضافة هذا إلى التكوين الأساسي على الرغم من أنه من السهل على مطوري TypeScript تشغيله. كنت سأضعه في إصدار هذا الأسبوع ، لكنني لم أدرك أنه تم تغيير هذا بعد.

تضمين التغريدة : +1:

لقد استخدمت التعليقات التوضيحية لتمييز خصائص كائن على أنه يمكن ملاحظته ، مما يحول الكائن البدائي إلى كائن يمكن ملاحظته (للمهتمين ، https://github.com/mweststrate/MOBservable/commit/8cc7fc0e20c000db660037c8b5c9d944fe4155d9).

ومع ذلك ، خاصة بالنسبة للخصائص ، فقد شعرت أنه من غير الطبيعي بعض الشيء أن يتم تطبيق التعليقات التوضيحية على النموذج الأولي ، وليس في مُنشئ الفئة نفسها ، وهذا يعني أنه من الصعب الحصول على القيمة الأولية ، أو حتى this . كان العمل حول ذلك هو إنشاء خاصية ، وفي أداة التجميع / المُعيِّن الخاصة بها ، نفذ المنطق الفعلي الذي كان من المفترض أن يقوم به التعليق التوضيحي ، نظرًا لأن this والقيمة متاحة في ذلك الوقت.

إلى جانب ذلك ، ميزة رائعة!

باستخدام Metadata Reflection API ، تمكنت من إجراء حقن تبعية للخصائص البسيطة.
يمكنك التحقق من التغييرات المطلوبة هنا https://github.com/matjaz/property-DI/commit/2b4835e100b72d954b57d0e656ea524539ac17eb.

لا ينبغي أن يكون __metadata decorator في الكود الذي تم استدعاؤه أولاً وقبل كل شيء مصمم الديكور؟ أردت إنشاء deocrator بسيط باستخدام البيانات الوصفية للفصل ، ولكن __metadata ('design: paramtypes'، [TYPES ....]) تم استدعاؤه على أنه الأخير ، لذلك لا يمكنني الحصول على هذه البيانات من Reflect

ufon هل يمكنك مشاركة الرمز الذي تبحث عنه؟

بالتأكيد ، هنا https://gist.github.com/ufon/5a2fa2481ac412117532

تعديل:
سيئتي ، هناك خطأ آخر في الكود الخاص بي ، لا يمكنني الحصول على أنواع حتى بعد إضفاء الطابع القانوني على الفصل

ufon ، لست متأكدًا من أنني أرى المشكلة بعد ذلك. __metadata هو العنصر الأخير في قائمة المصمم ، وهذا يعني أنه أول عنصر يتم تنفيذه ، وبالتأكيد قبل تنفيذ الحقن.

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

حيث يستخدم تعريف __decorate تقليل الحق في تنفيذ الزخرفة بترتيب عكسي.

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

هذا لمطابقة المواصفات ، حيث يتم تقييم المصممين (كتعبيرات) بترتيب الإعلان ، ولكن يتم تنفيذها بترتيب عكسي ، مما يسمح لمصممي الديكور الخارجي باستهلاك النتائج من المصممين الداخليين.

أرى ، آسف للإزعاج :) سيئتي ، هناك خطأ آخر في الكود الخاص بي ، لا يمكنني الحصول على أنواع حتى بعد إضفاء الطابع الرسمي على الفصل

كيف حالك الاستعلام عنهم؟ وهل لديك بوليفيل لـ Reflect.metadata؟

أضيفت إلى جوهر ...
Reflect.getMetadataKeys (البيت) ،
هذه النتائج خالية من المصفوفة ..

نعم ، أنا بحاجة إلى حزمة "تعكس بيانات وصفية"

يبدو أن polyfill يفقده ،

أعتقد أنني حصلت عليه ...
يتطلب نقل بعد رمز المساعد المطبوع عليه

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

لذلك ، في الوقت الذي يتم فيه إضفاء الطابع الرسمي على var __metadata ، لم يتم تحميل polyfill بعد

لكن لا يمكنني الحصول على هذه تتطلب قبل الرمز الذي تم إنشاؤه

EDIT: تم تحديث المحتوى .. عند تجميع وحدة مفردة ، لا توجد طريقة لتحميل polyfill قبل حل __metadata ، لأنه يتم دائمًا نقل التعليمات البرمجية التي تم إنشاؤها بواسطة الكتابة إلى أعلى الملف

أوه .. هذه قضية أكبر. المشكلة المسجلة رقم 2811 لتعقبها

حتى ذلك الحين تحتاج إلى reflect-metadata في وحدة أخرى (تحتاج إلى ملفين).
انظر https://github.com/matjaz/property-DI/

يبدو أن هناك تناقضًا في الاستدعاء مما يجعل من الصعب جدًا القيام بتطوير الزخارف ذات المعلمات المتغيرة / الاختيارية. كمثال:

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

@F()
prop: number;

في السابق ، يتم استدعاء F مع المعلمات (target ، propertyName ، propertyDescriptor) بينما في الأخير ، يتم استدعاء F مع المعلمات () ويتطلب أن يكون لديك وظيفة داخلية يتم إرجاعها والتي بدورها يتم استدعاؤها مع (target ، propertyName و propertyDescriptor).

كان من الممكن أن يكون _assumption_ الخاص بي هو أن كلا من F و @ F () سيكونان متكافئين وبالتالي لا يمكنك إجراء أي مكالمة إلا إذا كان المصمم يدعم 0 أو أكثر من المعلمات.

هذا مهم بشكل خاص في حالة:

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

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

يمكن حل هذا الأمر من خلال الاتصال صراحةً بـ @ F () بدلاً من @ F ولكن من السهل ارتكاب هذا الخطأ ثم الخلط عندما لا يعمل مصمم الديكور الخاص بك على الرغم من أن مظهره يجب أن يفعل.

في هذه الحالة أود أن أفعل ما يلي:

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

وانتهى من ذلك ، لكن بدلاً من ذلك يجب أن أفعل شيئًا مثل المثال الخام التالي:

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]);
}

وهو ألم حقيقي.

Tharaxis هذا السلوك حسب التصميم. @F و @F() غير متكافئين. يستدعي @F مصمم الديكور F ، حيث يستدعي @F() عامل التزيين F بقائمة وسيطات فارغة ، ثم يطبق المصمم الناتج.

المشكلة هنا هي أن المترجم يقارن توقيع مصنع الديكور F مقابل declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void; والذي ينتهي به الأمر ليكون قابلاً للتخصيص. أعتقد أننا بحاجة إلى فحص أقوى هنا للتأكد من أننا نلتقط هذه المشكلة. لقد سجلت # 3246 لإصلاح هذا. أعتقد أنك تفعل الشيء الصحيح ، ويجب على المترجم أن يكتشف الاستخدامات غير الصالحة لمصنع الديكور.

mhegazy ، لست متأكدًا من سبب حدوث ذلك ، ومع ذلك ، هل هناك بعض حالات الاستخدام التي تمنع الشخص من الحصول على ما @F و @F() ، حيث أنهما في النهاية استدعاء متطابق لوظيفة الديكور ، واحد منهم فقط يتضمن أيضًا استدعاءًا لوظيفة المصنع الخارجية؟ يبدو أنه يتم انتهاك مبدأ أقل قدر من الدهشة هنا لأن هذا بالتأكيد سلوك مذهل للغاية ولا أرى سبب وجوب وجود طريقتين لاستدعاء مصمم الديكور من منظور مستهلك واجهة برمجة التطبيقات.

بينما أحصل على ذلك من منظور JS ، هناك اختلاف (في أحدهما تقوم بتمرير مرجع دالة F والآخر تقوم بتنفيذ وظيفة ثم تمرير مرجع نتيجتها كمصمم) ، فأنا لست كذلك متأكد من أنني أفهم لماذا لا يمكن للمرء أن يكون لديه مجرد مزخرف يتم تمريره على أنه @F يطابق ضمنيًا (ويستدعي) المصنع كمصنع بقائمة معلمات فارغة؟

ليس لدى المترجم طريقة لمعرفة ما إذا كان مصنعًا أم مصممًا. إذا كان لديك هذا التوقيع:

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

هل هذا ديكور أم مصنع هل يُدعى بحجج فارغة أم لا؟

أكثر ما يمكن للمترجم أن يفعله هو التحقق من تطابق التوقيع عند تسميته بطريقة أو بأخرى ، وإعطاء أخطاء إذا لم يكن كذلك.

rbuckton لديه إصلاح لـ # 3246 والذي يجب أن يشير إلى الحالات التي لا يتم فيها استخدام الديكور الخاص بك كمصنع ، لذلك ترقبوا ذلك.

mhegazy ، ما أقوله هو أن استخدام مصمم الديكور (على @F أو @F() ) يجب أن يكون _ دائمًا_ استدعاءًا لوظيفة المصنع F ، والتي بدورها تُرجع نوع الديكور المناسب. لا يوجد تمثيل عالي المستوى لمصمم ديكور بدون مصنع تغليف.

بمعنى آخر ، يكون توقيع F دائمًا:

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

أو ما يعادله.

ثم يتم إجراء الاستدعاء @F بما يعادل @F() بواسطة المترجم. نظرًا لأن كلا من توقيع @F و @F() يجب أن يتطابق مع توقيع المصنع بشكل ما ، فإن هذا يحل مشكلة ارتباك الاستدعاء. هناك طريقة واحدة فقط لاستدعاء مصمم الديكور!

بالنظر إلى ما يلي:

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

@F()
property: number;

و

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

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

يفعلون نفس الشيء ولكن علي أن أعلنهم بشكل مختلف! ومع ذلك ، فإن إعلان وجود F بحيث يمكن أن يكون موجودًا في كلا الاتجاهين أمر مرهق حقًا ويجعل إنشاء معلمات ووثائق متسقة أمرًا مستحيلًا. إما أنك تختار أن مصمم الديكور الخاص بك يحتاج إلى استخدام مصنع أم لا ، ويجب على مستهلك واجهة برمجة التطبيقات (API) معرفة هذا التمييز مسبقًا للاستفادة منه.

Tharaxis إذا كنت أبحث عن مكتبة توفر F التي سيتم استخدامها كمصمم ديكور ، أتوقع تمامًا أن يكون @F و @F() أشياء مختلفة. تمامًا كما أتوقع أن يكون C و C() أشياء مختلفة - تشير الأولى إلى قيمة ، بينما تستدعي الثانية قيمة. يستخدم @F مصمم ديكور ، ويستدعي @F() وظيفة من شأنها إنشاء مصمم. هذه ليست ولا ينبغي أن تكون نفس العملية.

DavidSouther هل هناك أي سبب وجيه لماذا لا يمكن أو لا ينبغي أن يكون هذا هو الحال؟ لا يوجد فرق وظيفي بين استدعاء @F و @F() ولكن هناك فرق كبير جدًا بين كيفية تعريفهما وتوثيقهما ، ويضيف تعقيدًا إضافيًا إلى الاستدعاء الذي يجب أن يكون غير ضروري.

اقتراحي هو أنه لا ينبغي أن تكون هناك طريقتان لتعريف المصمم لأنه لا توجد حاجة ، ولا يجب أن تكون هناك حاجة لتعريف المصمم بأكثر من طريقة.

لا يوجد فرق وظيفي بين استدعاء F و @ F ()

أعتقد أن هذه هي نقطة الخلاف الرئيسية. لا أعتقد أن هذا صحيح. F إشارة إلى دالة ، F () هي إشارة إلى القيمة المرجعة لـ F عند استدعائها بمجموعة وسيطة فارغة (على سبيل المثال F.call(this, []) ) ؛ وهذان شيئان مختلفان وظيفيًا ومفاهيميًا.

Tharaxis @F و @F() أشياء مختلفة. هناك اختلاف في كيفية استخدامها ، والاختلاف في كيفية توثيقها ، والاختلافات في الاحتجاج التي هي ضرورية للغاية.

اسمحوا لي أن أسألها بطريقة مختلفة: لماذا يجب أن تكون كل وظيفة ديكور مصنعًا؟ باستخدام اقتراحك ، سيكون من المستحيل أن يكون لديك مصمم ديكور بسيط.

mhegazy بينما @F() ) ينتج عنه إغلاق وظيفي ونفقات إضافية من خلال إنشاء وظائف ديكور معزولة (ومكررة) واستدعاء @F يؤدي بشكل أساسي إلى مرجع وظيفة الديكور المشترك ، وأود أن أقول إن العزل من خلال الإغلاق سيكون "أكثر أمانًا" وأكثر اتساقًا ، مما يقلل من احتمالية حدوث مفاجآت.

DavidSouther سؤالك يعتمد على ما تحدده

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

أجد أن هذا الحد الأدنى من التدخل الجراحي نظرًا لأنه أكثر من سطرين فقط من "التركيب البسيط" ويحدد بشكل أكثر وضوحًا ما هي دعوات الديكور المتاحة. بالإضافة إلى ذلك ، نظرًا لوجود طريقة واحدة فقط لتعريف المصمم (ودعنا لا نستبعد قيمة التناسق) ، فمن المحتمل أن تستغرق ثانيتين أخريين تقريبًا للتخلص من ذلك مقارنة بـ "الصيغة البسيطة".

بالإضافة إلى ذلك ، هناك مشكلة أكثر إشكالية هي كما يلي:

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;

واحدة من هذه الأشياء ليست مثل غيرها. لن يعمل استخدام @F على الرغم من أنه يجب أن يكون بالقيمة الاسمية. ضع في اعتبارك ، تخيل أنني شخص ليس على دراية بالشكل الذي يبدو عليه الإعلان الأساسي لـ F ، ولكن بدلاً من ذلك عليك فقط معرفة أن F موجود وأنه يمكن أن يتطلب مجموعة اختيارية من الحجج. إن فرص إخطائي في استخدام @F ليست تافهة في ظل الآلية الحالية. يضع هذا عبئًا كبيرًا على المطور / الوثيق للتأكد من أن المستهلك يدرك أن @F لن يعمل (ولكن ربما @C سوف يفعل لأنه "مختلف" بطريقة ما).

إذا كنت أريد مصمم ديكور "مقاس واحد يناسب الجميع" ، حيث لا داعي للقلق لدى المستهلك ، يجب أن أفعل هذا الشيء المروع:

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;
}

وهو أمر مروع بصراحة. بالإضافة إلى ذلك ، أفقد كل المعلمات القيمة المعنوية ضد المصمم F منذ الآن يجب تعميمها.

هناك الكثير مما يمكن قوله عن أن وجود مصممي الديكور يكون سهلًا ومتسقًا في التحديد والتوثيق. دعنا لا نخدع أنفسنا بالاعتقاد بأن كل شخص يستهلك الكود الخاص بنا سيكون لديه نفس الدهاء والفهم مثلنا نحن الذين صانعي هذا الكود.

Tharaxis لقد فكرت في هذا مبكرًا في تصميم مصممي الديكور ، وأنا أفهم نقاطك المحددة. كماmhegazy وDavidSouther ذكر سابقا في هذا الموضوع، ويتسق مع سلوك القياسية وظائف في جافا سكريبت هذا السلوك.

أنت محق في أن أي محاولة لإنشاء وظيفة يمكن أن تكون بمثابة مصنع ديكور ومصنع ديكور يمكن أن تكون معقدة إلى حد ما. بشكل عام ، على الرغم من ذلك ، قد يكون من الأفضل استخدام أفضل الممارسات لاستخدام مصانع الديكور دائمًا ، وتوفير القواعد إلى linter لضمان اعتماد هذه الممارسة.

أيضًا ، لقد قدمت للتو PR # 3249 لمعالجة نقطتك السابقة فيما يتعلق بالتناقضات في التحقق من النوع لمصممي الديكور.

مرحبًا rbuckton ،

أنا واحد من هؤلاء المستخدمين غير المحنكين لمصممي الديكور الذين ذكرهمTharaxis ...

أعتقد أن السؤال الذي سأطرحه هو هل يجب أن يتوافق المصممون مع الوظائف؟ أي في حالة الدوال ، فإن إعادة this.f مقابل this.f () تبدو منطقية تمامًا بالنسبة لي لأنني أحيانًا أريد القيمة ، وأحيانًا أريد الشيء الذي ينتج القيمة.

في حالة المصممين ، لا يبدو الأمر واضحًا تمامًا بالنسبة لي على مستوى ميزة اللغة. أود أن أزعم أنني أريد فقط تطبيق decorator @ F ، لا أريد حقًا معرفة ما إذا كان قد تم تنفيذه كمصنع أو طريقة ثابتة. هذا ما لم أفقد بعض القدرة التي كان من الممكن أن يتمتع بها المصممون.

اعتذاري إذا كان ما سبق مضللاً أو جاهلاً ، فأنا جديد نسبيًا في عالم جافا سكريبت.

شكرا و تحياتي

يجب أن أطرح هذا السؤال أيضًا - هل من المنطقي الحفاظ على التكافؤ النحوي مع الدوال _if_ (وفقط إذا) لا يوجد سبب حقيقي للقيام بذلك بخلاف "لأنه يتم تعريفه باستخدام الدوال". أرى الديكور كميزة لا علاقة لها تمامًا بالوظائف التي _ تتحقق_ ليتم تعريفها باستخدامها.

في الوقت الحالي ، حقيقة أن @F و @F() ليسا متطابقين تسبب المشكلات التالية:

  • يحتاج المطورون إلى فهم الفرق بين @F و @F() ولماذا قد ينجح هذا أحيانًا ولماذا قد لا يعمل هذا أحيانًا (والحاجة إلى استخدام @F مقابل @F() يمكن أن يكون declare function A(params?: any): ParameterDecorator مقابل declare function B(target, name) ، @A لن يعمل ، لكن @A() سوف ، @B سيعمل لكن @B() لن يعمل ، لكن من الناحية الإدراكية فهما نفس الشيء ، تطبيق مصمم بدون وسيطات).
  • يتطلب حل المشكلة من مستوى الكود حلاً بديلاً يزيل قدرة الشخص على توثيق بنية استدعاء Decorator بشكل مناسب.
  • تعتبر إعادة البناء عملاً أكثر قليلاً إذا قمت بإنشاء "مصمم خام" ( @F ) وتريد الآن إضافة بعض المعلمات (ولكن اجعلها اختيارية للتوافق مع الإصدارات السابقة). وفقًا للطريقة الحالية ، ستحتاج الآن جميع هذه التطبيقات @F إلى إعادة تشكيلها إلى @F() - قد لا تتمكن من الوصول إلى بعضها داخل الكود - بينما يسمح لك الاستدعاء الضمني بالحفاظ على عمل الأشياء وتقييد تغيير إلى التعليمات البرمجية الخاصة بك.

Tharaxis أفهم أن التمييز بين @F و @F() يمكن أن يكون عبئًا معرفيًا كبيرًا على المستهلكين. ومع ذلك ، يبدو أنك تطلب تغيير الشفرة المنبعثة ، وبالتالي السلوك ، بحيث يتصرف الاثنان بشكل متساوٍ. من المحتمل أن يتعارض هذا مع اقتراح ES7 لمصممي الديكور ، حيث من غير المرجح أن يتم التعامل مع النموذجين بنفس الطريقة. لن يكون من الجيد أن يؤدي هذا إلى اختلاف.

نقطة أخرى هي أن الالتباس هنا يشبه الخلط بين تمرير دالة على أنها رد اتصال ، واستدعاء الوظيفة. إذا كان لديك هذا

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

قد يتم الخلط بين المستخدم والاتصال بـ takesCallback(callbackFactory) بدون استدعاء callbackFactory . هذا تمامًا مثل الارتباك الذي أشرت إليه مع المصممين ، ولكن إذا قامت اللغة بتطبيع هذين الشكلين لفعل الشيء نفسه ، فسيكون هناك فقدان في التعبيرية. في بعض الأحيان يكون التمييز مهمًا ويحتاج إلى الحفاظ عليه. لست متأكدًا مما إذا كان هذا ينطبق بشكل شائع على المصممين أيضًا ، ولكن من الناحية النظرية يمكن ذلك بالتأكيد.

JsonFreeman أنا لا أفهم حجة الخاص بك على الرغم من. أنت تقول أنه لا يمكنك جعل المصممين منطقيين ككيان خاص بهم لأن اقتراح ES7 موجود لمصممي الديكور ، ولكن هذا هو الشيء ، مصممي ES7 هم مجرد اقتراح ، وبقدر ما أعلم ، هم ' إعادة تستند جزئيًا إلى مزيج من أعمال الديكور التي وصفها كل من Google وأنفسكم ، أليس كذلك؟ لم يتم اتخاذ قرار بشأن أي شيء حتى الآن فيما يتعلق بكيفية عملهم ، ومن المحتمل أن يمر الاقتراح بالعديد من التكرارات قبل الموافقة ، فلماذا لا تجعلهم يعملون بطريقة متسقة في TS ثم (على الأقل حاول) الحصول عليها الأطراف المختلفة المشاركة في الاقتراح وراء الفكرة ، باستخدام الخبرة المكتسبة في TS كأساس؟ لن تكون هذه هي المرة الأولى التي ينفذ فيها TS ميزة ما فقط ليتم إعادة بنائها لاحقًا لأن مواصفات ES6 تتطلب سلوكًا مختلفًا قليلاً. ستواجه هذه المشكلة دائمًا طالما أنك تتبع مواصفات غير موجودة حتى الآن ولم يتم الاتفاق عليها بعد.

بالنسبة للمثال الخاص بك فيما يتعلق بالوظائف ، يبدو مرة أخرى أننا نخلط الوظائف مع الزخارف عندما تكون في الواقع (ويجب أن تكون) بنى مختلفة تمامًا. عندما أعمل مع دالة في JavaScript ، أفهم كيفية استخدام الوظائف وأفهم الفرق بين مرجع الوظيفة واستدعاء الوظيفة (ومتى قد أرغب في استخدام أحدهما مقابل الآخر) - وعندما أصف شيئًا ما كدالة ، لا يوجد أي لبس فيما يتعلق باستخداماتها. الزخرفة _لا _ وظائف ويجب ألا ترث سلوك الوظائف. الوظائف هي مجرد الطريقة التي يتم بناء الديكور عليها. هذا مثل القول بأن الفئات هي وظائف ، وهذا ليس هو الحال ، فالوظائف هي مجرد الطريقة التي نصف بها الفئات قبل ES6 لأنه لم يكن هناك طريقة أكثر وضوحًا متاحة. لا تأخذ الفصول الدراسية خصائص الوظائف ، ولا يمكنك استدعاء الفئات مثل الوظائف ، لكنك تعلن عنها باستخدام وظائف قبل ES6.

بغض النظر ، أشعر أنني استنفدت نقاط جدالي حول هذه القضية. سآخذ فقط للعمل حول الاختيار. في الكود الخاص بي ، سأستخدم المصانع دائمًا من أجل الاتساق الخاص بي. ما زلت أعتقد أن معاملة مصممي الديكور حرفيًا كوظائف من المرجح أن يسبب الكثير من الإحباط في المستقبل ، لكن هذا أنا فقط.

mhegazy هذه هي نفس المشكلة التي طرحتها على https://github.com/jonathandturner/decorators/issues/16 أعتقد أن هذا شيء يجب التفكير فيه. كما هو الحال ، أتوقع أن يكون اختيار التصميم هذا موضوعًا للعديد من منشورات المدونة التي تحمل عنوانًا مشابهًا أيضًا "ES7 Decorator Pitfalls".

Tharaxis ، أتفق مع

أما "الديكور ليس حجة وظائف" ، إذا لم أكن مخطئا ، فنحن لا نتحدث عن مصممي الديكور بأنفسهم ، نحن نتحدث عن مصانع الديكور. وبغض النظر عن أي تمييز بين الزخارف والوظائف ، أعتقد أن المصانع _مصانع الديكور_ هي في الواقع مجرد وظائف. ويبدو أنك تطلب من المترجم أن يقوم تلقائيًا بإنشاء مكالمة إلى مصنع ديكور ، وهي وظيفة عادية. إذا حدث ذلك ، فلن تكون هناك طريقة للمبرمج للتمييز بين مصنع الديكور ومصمم الديكور.

أيضًا ، الشيء الجميل في معاملة المصممين كوظائف هو أنه يمكن للمستهلك أن يطبقها كمصمم ديكور أو ببساطة عن طريق تسميته كما يراه مناسبًا.

يدور الجدل JsonFreeman حول الوضع الحالي حيث توجد طريقتان لوصف واستدعاء مصمم الديكور ، واحدة من خلال وظيفة المصنع ، والأخرى كوظيفة "خام" (والتي تكون في حالة المصنع نتيجة لاستدعاء المصنع ) ، وكان السؤال أكثر حول "لا ينبغي أن يكون هناك طريق واحد ، وأن تكون المصانع على هذا النحو".

ما أطلبه هو نعم ، ألا يمكننا فقط أن نجعل المترجم يحول @F إلى ما يعادل @F() call وأن يكون التحقق من النوع يتطلب قائمة وسيطات من 0 ... n معلمات عند استخدام بناء جملة غير محصورة بين قوسين. ربما يمكنك توضيح المقصود بعبارة "... لن تكون هناك طريقة للمبرمج للتمييز بين مصنع الديكور ومصمم الديكور ..." ، لأنني أعتقد أنه من السهل جدًا التمييز. المصمم دائما هو رد المصنع واسم المصنع هو اسم المصمم ... ليس بهذه الصعوبة ام انا سوء تفاهم؟

بالنسبة إلى نقطتك الأخيرة حول السماح للمستهلك بتطبيق المصمم فقط ، إذا تم وصفه جيدًا أن جميع مصممي الديكور يستخدمون المصانع ، فمن السهل جدًا استدعاء مصمم الديكور بنفسك ، فأنت تفعل فقط <decorator name>(<argument list>)(target, name) مقارنة بـ <decorator name>(target, name) كمثال. ضع في اعتبارك أن فرض استخدام المصانع يعني أن المثال السابق سيعمل دائمًا ، بينما عدم فرضه سيؤدي إلى عدم نجاح المثال الأخير في بعض الأحيان ، ويعتمد كليًا على كيفية تنفيذ المصمم - صداع ينتظر حدوثه.

أشعر أنه من الضروري الإشارة إلى أنه ليس لدي مشكلة مع المصممين الذين يستخدمون الوظائف ، لكن مشكلتي هي أن وجود طريقتين لوصف نفس الشيء يؤدي إلى مشكلات الاتساق. خاصة عندما تعني هاتان الطريقتان أيضًا أن طريقة الاستدعاء يجب أن تختلف. هذا هو التفاوت الذي يعيق كل شيء من إعادة البناء إلى الاتساق اللغوي.

يجب أن تكون مشكلة إعادة الهيكلة التي وصفتها لبعض المنشورات السابقة أكثر من كافية لسبب وجوب فحص الطريقة الحالية.

مرحبًا بالجميع ، فقط 1.5 سنتًا نهائيًا يستحق من مستخدم منتظم على غرار ما قاله

سأكون أكثر من سعيد بالاقتراح الحالي إذا:
أ) الكون يفرض ذلك.
ب) يفقد المصممون قدرات مهمة إذا كانت الأمور مختلفة.

الأحدث هو بالطبع حكم قيمي ، وستعتمد الإجابة عليه إلى حد ما على نوع المطور الذي أنت عليه (أي مستخدم عام / مستخدم خبير ، إلخ). أنا في الفئة السابقة وأنا عمومًا منتشر بشكل ضئيل عبر لغات وأطر متعددة. لذلك بالنسبة لي ، لن تتضمن "القدرات المهمة" المرونة في كتابة المصممين بطريقتين مختلفتين. ستكون أمثلة جميع المفاضلات رائعة إذا كانت موجودة.

من الناحية المثالية ، سيكون أمرًا رائعًا أن يكون @ F و @ F () متسقين بغض النظر عن كيفية تنفيذ أدوات الديكور ، ولكن إذا لم يكن الأمر

شكرا و تحياتي

يبدو أن هذا الطلب يتوقف على فكرة أن مصانع الديكور هي الطريقة المتعارف عليها لاستخدام أدوات الديكور ، لكنني لا أرى كيف يسمح هذا للمستخدم بتحديد واستخدام الزخارف الخام. إذا قمت بتعريف مصمم الديكور F ، وتم التعامل مع التطبيق @F على أنه @F() ، فإن نتيجة استدعاء F تُستخدم كزينة ، بدلاً من F نفسها. هل تقترح أن نعطي خطأ في مكان ما إذا حاول شخص ما تطبيق ديكور خام بدلاً من مصنع ديكور؟

تبدو هذه الفكرة وكأنها ستعكس التكوين الطبيعي لمصانع الديكور ومصانع الديكور. يشعر المصممون بالتأكيد وكأنهم البناء البدائي هنا ، حيث تكون مصانع الديكور طبقة من التجريد المبني فوق المصممين. هم مجرد نمط ، لا أكثر. إذا أصبح مصنع الديكور بدلاً من ذلك الشيء المتعارف عليه ، البدائي ، فإن الناس سيحددون مجموعة من مصانع الديكور ، التي لا تقبل الحجج وتعيد مصمم الديكور المسطح. سيبدأ هذا في الشعور بالسخف الشديد ، وسيعكس الحدس الطبيعي لما يعتبر أساسيًا وما يعتبر أكثر تعقيدًا.

الشيء الوحيد الذي أحذر منه مع مصممي الديكور هو الإفراط في السحر. أنا شخصياً أشعر بالتوتر عندما لا أفهم ما يفعله الكود ، وإذا كان المترجم يضيف سراً استدعاءات إضافية لم يكتبها المبرمج ، فهذا يبدو لي وكأنه الكثير من الفودو.

مرحبًا JsonFreeman ،

كما ذكرتُ سابقًا ، أفضّل دائمًا أن يكون القبح مع مؤلف الديكور بدلاً من المستخدم. ومع ذلك ، أوافق على أن الكثير من المصانع غير المجادلة هي مجموعة كبيرة من القبيح. هل يمكن استخدام المصمم لإصلاح هذا؟ على سبيل المثال

// 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) {...}

على أي حال ، إذا تم العثور على مثل هذا النهج ليكون منطقيًا ، فإنه يتمتع بميزة أن التعليق التوضيحي يوثق الغرض من الوظيفة. أي أنه يزين.

هتافات

مرق جيد ، مصممون للمساعدة في تحديد الديكور ، حالة خطيرة من Typeception.

JsonFreeman لست متأكدًا من أن الدوال الصفرية هي بالضرورة أكثر بشاعة من وجود العديد من وظائف (الهدف ، الاسم) بدلاً منها. إذا كان هناك أي شيء على الأقل من الوظائف ذات المعلمات الصفرية توفر مستوى من الدقة / الوضوح تفتقر إليه الطريقة الأخرى (نظرًا لأن المعلمات لا تتطابق أبدًا مع الاستدعاء في الحالة الأخيرة) ، وفوق ذلك يوفر هدفًا واحدًا للتوثيق بدلاً من ذلك من مستوى غير ضروري من عدم الاتساق. أرى أيضًا إحجامًا عن السير في أي طريق واحد بسبب التعقيد "المحتمل" المتصور ، لكنني أقول في ضوء التعقيد "الواضح" الحقيقي للغاية الذي يفرضه التنفيذ الحالي على جانب الاستهلاك ، ينبغي للمرء أن يخطئ أكثر من الجانب من الواضح مما هو ممكن.

الخيار الآخر هو إلزام المصممين الذين يطلق عليهم @F بمطابقة إما النمط الخاص بـ ClassDecorator أو MethodDecorator أو PropertyDecorator أو ParameterDecorator أو دالة مصنع وسيط 0..n تقوم بإرجاع ClassDecorator أو MethodDecorator أو PropertyDecorator أو ParameterDecorator. ومع ذلك ، فإنني أشعر أن هذا التنفيذ قد يتسبب في أخطاء أخرى (ماذا لو كان لديك وظيفتان متعارضتان ، أيهما سيعتبر أفضل تطابق ممكن؟) وسيضيف فقط تعقيدًا لا داعي له داخل المترجم. ببساطة تحويل مكالمات @F إلى @F() سيكون الحل الأبسط وسيحل المشاكل المختلفة المذكورة.

آسف ، للتوضيح ، لم أكن أدعي أن الحل الخاص بك معقد. قصدت أن استدعاء المصمم تلقائيًا قبل تطبيقه غير شفاف. الاستدعاء المُدرج غير مرئي للمستخدم ، وأشعر أن العديد من المستخدمين لن يتوقعوه.

أعتقد أن الوضع الحالي ليس معقدًا أيضًا. كما أشرت ، فإنه يسمح لمؤلفي المكتبات بأن يكونوا غامضين أو متشائمين حول ما إذا كان من المفترض أن يتم تطبيق وظيفتهم كمصمم ديكور. سأمنحك ذلك. لكن المكتبة الجيدة ستوضح ذلك.

في المخطط الذي تقترحه ، حيث تقوم بالاستدعاء تلقائيًا ، ماذا يحدث عندما تستخدم تعبير مزخرف تعسفي بدلاً من مجرد معرف؟ هل يتم استدعاء ذلك أيضًا؟

سأوافق على أنه ما لم يتم توثيقه بخلاف ذلك ، فمن المحتمل أن يكون الاستدعاء الضمني مفاجئًا ، ولكن فقط لأولئك الذين لم يستخدموا مفاهيم مثل سمات C # وما شابه ذلك.

هل يمكنك أن تشرح ما تعنيه بتعبير مزخرف اعتباطي؟

مرق جيد ، مصممون للمساعدة في تحديد الديكور ، حالة خطيرة من Typeception.

دعوة عادلة. يخدمني بشكل صحيح للحصول على تعليق سيئ التفكير في وقت متأخر بعد ظهر يوم عطلة نهاية الأسبوع. تعلمت الدرس. Internet.undo ().

وجهة نظري هي أنه إذا اتضح أن بناء جملة موقع الاستدعاء المتسق يتطلب استخدام المصانع ، فأنا أكثر من سعيد بذلك. أنا بلا شك أكتب مصممًا لإزالة لوحة الغلاية. مرة أخرى ، أفضل القليل من الألم عند كتابة الديكور على الألم المتكرر باستخدامهم (وإن كان الألم محتملاً في هذه المرحلة). سوف يختلف الآخرون.

ألا توجد مشكلة أيضًا في تحسين واجهة برمجة التطبيقات؟ لا يمكن لمصمم الديكور الذي تم إنشاؤه بدون مصنع إضافة معلمات اختيارية في وقت لاحق ، ومن ثم أتوقع @F و @F2() في مستقبلي.

لا أرى أيضًا أنك ستحصل على هذا السيناريو عند استخدام f و f() ، فهما حالات استخدام مختلفة على جانب الاستهلاك. في حالة الديكور ، أقوم دائمًا بتطبيق / استدعاء المصمم على الهدف في ذلك الوقت وهناك ، وهناك دائمًا استدعاء طريقة يحدث خلف الكواليس.

لكن جوهر هذا بالنسبة لي هو مسألة قابلية الاستخدام ، فعندما أقوم بتطبيق مصمم ديكور ، لا أريد أن أضطر إلى البحث في Google لمعرفة كيف قام المؤلف بتطبيقه - أنا مهتم بالسلوك ، وليس العبوة.

هتافات

مجرد ملاحظة أخيرة للتلخيص وبعد ذلك سألتزم الصمت. باختصار ، هذه مجرد مشكلة تصميم تفاعل بالنسبة لي. أنا حريص حقًا على رؤية مصممي الديكور من الخارج وليس العكس.

بصفتي رجل UI / UX ، أرى هذا كثيرًا. لقد عملت مع مطورين موهوبين اقترحوا حلول واجهة المستخدم التي من شأنها أن تؤذي المستخدمين (أحد الأمثلة كان زري حفظ في حالة واحدة لحل تعقيد المعاملة - مرة أخرى رجل ذكي وإنسان جيد). أعتقد فقط أنه عندما تكون ركبتيك عميقًا في منطق تفاصيل التنفيذ المعقد ، قد يكون من الصعب نسيان ما تعرفه ورؤيته من خلال عيون المستخدم العادي.

الآن إذا كنت مخطئًا تمامًا كمتوسط ​​، أو إذا كان التعقيد يفرض التصميم الحالي ، فكل شيء جيد ، سأضطر فقط إلى تشغيل ذهني والتعلم.

هتافات

إذا لم يكن مصمم الديكور الخاص بك معرّفًا ، ولكن هناك تعبير آخر ، فهل يمكنك استدعاءه تلقائيًا؟ على سبيل المثال ، لنفترض أنه كان مصممًا. OR-ed مع تعبير دالة رجعية. شيء مثل:

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

هل تقوم بعد ذلك باستدعاء هذا تلقائيًا؟ سيعطيك هذا نتيجة خاطئة لأنك في نهاية المطاف تستدعي المصمم الافتراضي قبل تطبيقه:

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

هذا لا يبدو الحق.

JsonFreeman ، هل تسمح صيغة

بعد قولي هذا ، أفترض أن الطريقة الوحيدة التي ستعمل عندها ستكون إذا تم تقييم التعبير التعسفي نفسه لنفس بنية المصنع ، لذلك:

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

أوافق على أنه يؤدي إلى أن تضطر إلى وضع القليل من القطع الصغيرة حول مصمم الديكور التعسفي الخاص بك ، لكنني أعتقد أن المرء لديه مشكلات أكبر من إضافة () => إذا كنت تستخدم تعبيرات تعسفية كمصممون.

ملاحظة: من الواضح أنني لم أقصد أن بناء جملة lambda ستكون الطريقة الوحيدة للإعلان عنها ، ولكن () => أجمل قليلاً من function() { return function(target) { /*...*/ } } .

آسف حقًا لمقاطعة هذا المصمم الذي يدعو إلى مناقشة بناء الجملة ، ولكن هل يمكن لأي شخص توضيح ترتيب تسمية تعبيرات المصمم رسميًا؟ على وجه الخصوص ، على غرار نوع الهدف للديكور ، موضع العضو المستهدف في المصدر الأصلي وترتيب المصممين على هدف واحد.

billccn يتم تطبيق الديكورات من الأسفل إلى الأعلى. لذلك في شفرة المصدر الأصلية إذا كان لديك

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

سيطبق هذا أولاً G على الطريقة ، ثم يطبق F على النتيجة. هل هذا ما تسأل عنه؟

ماذا عن هذا:

<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;
}

يتبعون ترتيب النطاق ، لذا فإن جميع الخصائص / الطرق أولاً ، بترتيب الإعلان ، ثم الفئة الأولى. على سبيل المثال B، C، D، E، F، A.

يمكنك رؤية الكود الذي تم إنشاؤه هنا .

يبدو أنه ليس من الممكن حاليًا تزيين خصائص المعلمات. هل يمكن دعمهم؟

تشبه خصائص المعلمات constructor(private prop: Type) ، حيث يتم التصريح عن خاصية (حقل) ومعلمة معًا. تكمن المشكلة في أنه يمكن تزيين كل منهما ، لذا قد يلزم اختراع بعض القواعد اللغوية التخيلية.

سؤال: هل يمكن استخدام أدوات الزخرفة لتعديل سلوك أسلوب الكائن البسيط ، مثل ...

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() {}
};

... وإذا لم يكن كذلك ، فلماذا؟ سيكون مفيدا حقا.

ليس بعد ، لكننا نفكر في ذلك. rbuckton قد يكون لديه المزيد من التفاصيل.

هل لي أن أسأل لماذا لا يستطيع المصمم تغيير نوع النتيجة المزخرفة من النوع الذي يتم تزيينه؟

على سبيل المثال ، يمكن اقتراح MethodDecorator بدلاً من ذلك على النحو التالي:

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

لذلك يمكن أن يكون المصمم أكثر مرونة في الاستخدام ويعمل إلى حد ما مثل الماكرو. يمكن تحديث نوع الفئة / الحقل المزخرف وفقًا لنوع إرجاع الديكور ، بحيث يظل هذا النوع من الأمان محفوظًا.

أعلم أن https://github.com/jonathandturner/brainstorming/blob/master/README.md#c4 -defining-a-decorator ذكر أن نوع الإرجاع يجب أن يكون هو نفسه. لكن type validity ليس وسيطة صالحة هنا ، IMHO. أولاً ، يمكن للمصممين في JavaScript تغيير نوع الفئة / الحقل ، لذلك لا توجد مشكلة توافق بين TS و JS. ثانيًا ، يتم تطبيق الديكورات بشكل ثابت ، يمكن لمجمع TS التفكير في نوع الحقل الأصلي ونوع الحقل المزخرف في تحديد الموقع.

HerringtonDarkholme أود أن أقول إن هذا يحتاج إلى تتبع في اقتراح مختلف. السبب الرئيسي هو طريقة تفسير المترجم للأنواع من خلال الإعلانات. بمجرد الإعلان عن نوع ما لا يمكن تغييره. إن إضافة متحولات النوع في المزيج يعني أننا بحاجة إلى حل هذه المشكلات لأننا نحل الإعلان الذي يمكن أن يصبح مشعرًا.

mhegazy لذا ، هل يمكنني أن أفهم هذا كحل وسط لسهولة التنفيذ ، وليس تصميمًا متعمدًا؟

وفقًا لهذا الاقتراح ، يستعيد المصممون القدرة على تشغيل الكود في وقت التصميم ، مع الحفاظ على بناء جملة تعريفي. لذلك يجب أن يكون الرمز التالي
صالح في JavaScript في المستقبل ، ولكنه غير صالح في TypeScript اليوم (ومع ذلك قد يتم قبوله بواسطة TS يومًا ما ، أليس كذلك؟).

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)

أعلم أن فرص دعم هذه الميزة صغيرة. لكني أريد أن أؤكد أن هذه ليست قصة مشابهة مثل كتابة structural مقابل nominal .

الاختيار الحالي هو أنه يجب عليك إرجاع شيء ما من المصمم الخاص بك يمكن تخصيصه للهدف. الجزء المفقود هو أننا لا نلتقط أي إضافات للنوع. لا أعتقد أن لدينا فكرة عن كيفية القيام بذلك ، لكننا لم نفكر في الأمر أيضًا. لذلك أعتقد أنه اقتراح عادل ، لكن تكلفة تنفيذه قد تكون عالية جدًا.

من الناحية المثالية ، أعتقد أن النوع الذي يعيده المصمم يجب أن يكون مطابقًا للهدف. ليس هناك ما يخبرنا ما إذا كنت ستستخدم النوع المزخرف في مصدر أو موضع هدف في مهمة.

على الرغم من أنني أعتقد أننا يجب أن ندمج نوع إرجاع الديكور والهدف ، نوع مثل mixin.

مجرد فكرة وظائف إضافية. نظرًا لأن ناتج مترجم TypeScript هو JavaScript ، فهناك بعض اللغات المشابهة لـ Java ، مثل Xtend

يمكنك التعرف على بعض الأفكار الشيقة في هذا المشروع. ابحث عن التعليقات التوضيحية النشطة "تسمح التعليقات التوضيحية النشطة للمطورين بالمشاركة في عملية ترجمة كود مصدر Xtend إلى كود Java عبر المكتبة"

سيكون التحكم في إخراج TypeScript عبر أدوات التزيين ميزة رائعة حقًا!

يجب أن يكون مصممو الواجهات ممكنًا.

shumy المشكلة هي أن الواجهات لا توجد في وقت التشغيل بأي شكل من الأشكال ، ويعمل المصممون فقط في وقت التشغيل.

هل هناك سبب لمعاملة مصممي العقارات بشكل مختلف عن أسلوب الديكور من حيث القيمة المرتجعة؟ (بابل لا).

ما أعنيه هو أنه إذا كنت أرغب في تحديد وظيفة لممتلكات عبر مصمم الديكور ، يجب أن أفعل هذا:

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

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

في حين تطلب Babel إرجاع الواصف:

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

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

هذا يجعل من الصعب كتابة مصمم في TypeScript وهو جزء من مكتبة سيتم استخدامها من Babel.

أقترح أن يتم التعامل مع مصمم الممتلكات بشكل مماثل لمصمم الطريقة ، ويجب تطبيق القيمة المرجعة لمصمم الديكور عبر Object.defineProperty . سيسمح هذا أيضًا بتعدد الزخارف في خاصية واحدة ، تمامًا مثل الطريقة.

الحل البديل في الوقت الحالي (لتوافق Babel) هو إرجاع الواصف من المصمم بالإضافة إلى تعيين الخاصية ، ولكن يبدو أن هذا مضيعة للوقت دون داع:

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

mhegazy هل

sccolbert في TypeScript ، اخترنا عدم السماح باستخدام واصفات الخصائص للمصممين على خصائص البيانات ، حيث يمكن أن يؤدي ذلك إلى حدوث مشكلات في وقت التشغيل نظرًا لحقيقة أن أي "قيمة" محددة بواسطة الواصف سيتم تعيينها على النموذج الأولي وليس على المثيل . في حين أن المثال أعلاه لن يمثل مشكلة بشكل عام ، ضع في اعتبارك ما يلي:

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 (!)

يوجد اقتراح لإصدار مستقبلي من ES لدعم خاصية "مُهيئ" في الواصف ، والتي سيتم تقييمها أثناء المنشئ. يمنحك ذلك القدرة على التحكم فيما إذا تم تعيين القيمة على النموذج الأولي أو تخصيصها لكل مثيل.

في الوقت الحالي ، يمكنك التغلب على هذا القيد عن طريق الاتصال بـ Object.defineProperty مباشرةً ، كما هو موضح في المثال الوارد في تعليقك. سنواصل التحقيق فيما إذا كان سيتم تخفيف هذا التقييد في المستقبل.

@ rbuckton شكرا! هل أنتم يا رفاق تجريون محادثات مع بابل لتتقاربوا على نفس الدلالات؟ أعتقد أن هذا هو أهم شيء.

لماذا قد يكون من المفيد استخدام مصمم لتعيين قيمة لنسخة معينة؟ أليس هذا هو الغرض من مهيئ الخاصية؟

حالة الاستخدام الخاصة بي أكثر تعقيدًا من المثال. أنا في الواقع أستخدم المصمم لتعريف أداة تحصل على كائن يعيد كائنًا مرتبطًا بسياق الخاصية this للخاصية ، بحيث يكون لهذه الأساليب الموجودة على الكائن المذكور إمكانية الوصول إلى المثيل الذي تم تعريفه فيه.

يمكنك التفكير في هذا على أنه محاكاة بروتوكول الوصف في Python ، حيث يستدعي الوصول إلى الأسلوب bar المحدد في الفئة Foo خلال المثال foo (على سبيل المثال foo.bar ) __get__ للدالة التي تُرجع BoundMethod . عندما يتم استدعاء هذا الكائن ، يتم استدعاء الوظيفة الأساسية باستخدام self كوسيطة أولى ، والتي في هذه الحالة هي foo . Javascript ليس لديها هذا المفهوم ، ولهذا السبب يتعين علينا تمرير حوالي thisArg والاتصال بـ function.bind كل مكان.

بالنسبة لحالتي ، فأنا لا أحدد الطرق ، ولكن إشارة آمنة من النوع. ها هو المصمم:
https://github.com/phosphorjs/phosphor-signaling/blob/1.0.1/src/index.ts#L144

عند الوصول إلى الخاصية ، تقوم بإرجاع تنفيذ ISignal والذي يرتبط بسياق المالك this . يسمح هذا للإشارة بالرجوع إلى المثيل الذي تم تعريفها فيه:
https://github.com/phosphorjs/phosphor-signaling/blob/1.0.1/src/index.ts#L263

في الواقع ، أنا أستخدم المصمم كاختصار لهذا المكافئ المطول:

class Foo {
  valueChanged: ISignal<number>;
}

defineSignal(Foo.prototype, 'valueChanged');

تضمين التغريدة

لا يُسمح بالديكور عند استهداف ES3

لماذا ا؟ لا أرى أي شيء يمنع استخدام __decorate في ES3.

يستخدم واصف الخاصية ، وهو غير متوفر في ES3
لو 4 سبتمبر. 2015 02:03 مساءً ، "Koloto" [email protected] بريد إلكتروني:

rbuckton https://github.com/rbuckton

لا يُسمح بالديكور عند استهداف ES3

لماذا ا؟ لا أرى أي شيء يمنع استخدام __decorate في ES3.

-
قم بالرد على هذا البريد الإلكتروني مباشرة أو قم بعرضه على GitHub
https://github.com/Microsoft/TypeScript/issues/2249#issuecomment -137717517
.

sccolbert قد يكون من الأفضل لك استخدام وكلاء ES6 بدلاً من مصممي العقارات.

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

متصفحات DavidSouther لا تدعم الوكلاء حتى الآن :(

cybrown نعم ، يستخدم واصف الخاصية للطرق

ويمكن استخدام واصف خاصية وهمي للطرق عند استهداف ES3. شيء من هذا القبيل { writable: true, enumerable: true, configurable: true } . لذلك لا أرى أي سبب لعدم دعم ES3.

sccolbert فهمت. منطقي. بالمناسبة ، تعمل TypeScript على تحسين _ هذه_ الكتابة للوظائف والطرق. أتساءل عما إذا كان ذلك سيكون مفيدًا هنا. على الرغم من أنني أفترض أن الكتابة ليست هي المشكلة بالنسبة لك ، إلا أنها دلالات وقت التشغيل.

JsonFreeman محسّن _this_ أصوات الكتابة مثيرة للاهتمام لبعض حالات الاستخدام الأخرى الخاصة بي. هل لديك المزيد من المعلومات حول ذلك؟

أعتقد أن المناقشة الأكثر تطورًا حول هذه الكتابة هي # 3694.

هتافات!

خطأ TS1207: لا يمكن تطبيق أدوات التزيين على عدة موصّلات الحصول / المجموعة التي تحمل الاسم نفسه.

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

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

الكود أعلاه غير مسموح به حتى لو كان أكثر منطقية مقارنةً بـ

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

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

يتم تعريف Getter و setter في مكالمة واحدة إلى Obect.defineProperty. هذا بالأحرى js quirk ، إعلان المجموعة والحصول على الرغم من انفصالهما ، هو في الحقيقة نفس إعلان الملكية. التحقق من الخطأ في المترجم هو تنبيه المستخدمين عند التفكير فيهم بشكل منفصل ؛ يتم تطبيق الزخرفة مرة واحدة فقط على واصف الممتلكات.

فقط أتساءل لأن المترجم يمكنه الشعور بالحصول على نفس الاسم والتثبيت في كائن واحد.
أو ربما علامة خيار لإخبار المترجم بدمجها وترك رسالة تحذير بدلاً من إلقاء الخطأ.

اشكرك

TakoLittle : يرجع سبب عدم قيامنا بهذا اليوم جزئيًا إلى طريقة

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

تقريبا:

F(G(X))

تتفكك تركيبة الديكور عندما تقوم بتزيين كل من الحاصد والمُعد:

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

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

كيف يتم إنشاء F و G هنا؟ هل يستند فقط إلى أمر المستندات (على سبيل المثال ، F(G(X)) )؟ هل كل مجموعة من أدوات الزخرفة الخاصة بالحاصل والواضع منفصلة ، ثم يتم تنفيذها بترتيب المستند (أي G(F(X)) )؟ هل يشير get و set أي طلب معين (على سبيل المثال ، هل get دائمًا قبل set أو العكس)؟ حتى نتأكد بنسبة 100٪ من أن النهج الأكثر اتساقًا الذي لا يفاجئ المستخدمين ، أو أن يكون لدينا نهج موثق جيدًا يمثل جزءًا من اقتراح مصممي الديكور مع المرحلة الثانية على الأقل أو قبول أفضل في ECMA-262 ، نشعر أنه من الأفضل كن أكثر تقييدًا وأخطأ هنا لأنه يسمح لنا بتخفيف هذا التقييد في وقت لاحق دون إدخال تغيير كسر يمكن أن يمر بسهولة دون أن يلاحظه أحد وربما يؤدي إلى سلوكيات غير متوقعة في وقت التشغيل.

rbuckton شكرًا جزيلاً لك على الشرح التفصيلي
فريق TS عمل عظيم !! ^ ^ د

أين توثيق هذا؟ والاهتمام بربط تنفيذ الالتزام؟

شكرا.

mhegazy ما هي حالة تنفيذ أحدث إصدار من المواصفات. أنا أفهم أن هناك بعض التغييرات.

تتبعت هذه المشكلة النسخة الأصلية من الاقتراح. منذ اكتمال هذا نحن نغلق هذه المسألة. بالنسبة لأي تحديثات على المواصفات ، سنقوم بتسجيل المشكلات الجديدة وتحديد جميع التغييرات العاجلة. لا أعتقد أن الاقتراح في مكان الآن لنكون جاهزين للقفز عليه. نحن نعمل عن كثب مع wycats بشأن الاقتراح الجديد.

omeid ، يمكنك العثور على الوثائق على https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Decorators.md

mhegazy شكرا لك على التحديث. أود أن أبقى على اطلاع. عند إنشاء الإصدار الجديد لتحديث المواصفات ، يرجى ربطه هنا حتى يتم إخطاري ومتابعته. يستخدم مجتمع Aurelia استخدامًا مكثفًا لمصممي الديكور وسنرغب في المزامنة مع كل من TypeScript و Babel في التحديث. مرة أخرى ، شكرًا على العمل الرائع الذي يقوم به فريق TS!

زخرفة الوظيفة تحتاج بالطبع.
هل توجد أيضًا خطط لتزيين أشياء أخرى في الكود؟

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات