object
يصف هذا الاقتراح نوعًا أوليًا جديدًا للطباعة على الكتابة object
.
تحتوي JavaScript core api على بعض الوظائف التي تأخذ object
كمعامل:
Object.getPrototypeOf
Object.getOwnPropertyDescriptor
Object.create
لا توجد حاليًا طريقة في الكتابة المطبوعة لمنع تمرير النوع الأولي الآخر ( string
، number
، إلخ ...) إلى تلك الوظائف.
على سبيل المثال ، Object.create('string')
عبارة عن نص مكتوب صالح تمامًا ، حتى لو انتهى بخطأ.
سيسمح إنشاء نوع بدائي object
بنمذجة توقيع هذه الوظيفة بشكل أكثر دقة ، وكل دالة تشترك في قيد مماثل.
النوع object
يعادل {}
مطروحًا منه قابلية التخصيص للنوع الأساسي الآخر ، وهذا يعني أن:
object
object
أي نوع غير أساسي إلى {}
و any
هذا السلوك متناسق مع طريقة عمل جافا سكريبت ، فالنوع يمثل كل قيمة تحترم القيد typeof value === 'object'
plus undefined
.
يجب تقديم نوع جديد من الحراس مقابل object
: typeof value === 'object'
.
اختياريًا ، يمكن للمترجم أيضًا قبول المقارنة مع وظيفة المصبوب Object
: Object(value) === value
.
سيكون من المفيد سرد بعض واجهات برمجة التطبيقات بخلاف وظائف Object.
التي ستستفيد من ذلك.
في javascript core api باستثناء Object
ربما ستستفيد بعض بنيات es6 من هذا (WeakMap ، Proxy إلخ).
ولكن على سبيل المثال ، ستكتسب كل وظيفة مجموعات شرطة null
، ImmutableJS ، Mori إلخ.
تحرير: تعمل مجموعة التسطير السفلي مع أي نوع
نوقشت في اجتماع مراجعة الاقتراح. كل هذا منطقي ، لكننا بحاجة إلى تبرير تعقيد النوع البدائي الجديد بعدد الأخطاء / ثراء الوصف الذي يمكنه توفيره. بشكل أساسي ، المزيد من الأمثلة على واجهات برمجة التطبيقات التي لا يمكنها العمل على الأساسيات ، خاصة تلك التي ليست "خبيرة" لواجهات برمجة التطبيقات (مثل الوكلاء)
نشر كمرجع أكثر من توصية: غمزة:
interface String { _primitiveBrand?: string; }
interface Boolean { _primitiveBrand?: boolean; }
interface Number { _primitiveBrand?: number; }
interface ObjectOnly { _primitiveBrand?: void; }
function fn(x: ObjectOnly) { }
// Error
fn(43);
// Error
fn('foo');
// OK
fn({});
// OK
fn(window);
+1 على هذا الاقتراح. لن أعتبر أن WeakMap
واجهة برمجة تطبيقات "خبير" ، لكنني أعتبرها سببًا كافيًا لتنفيذ ذلك. نظرًا لأن وقت التشغيل يميز بين أنواع الكائنات والأنواع الأولية ، فمن المنطقي أن يكون لديك ميزة في TypeScript لتمييزها أيضًا.
سيحل هذا الاقتراح أيضًا مشكلة كتابة "أكياس الكائنات" حيث تكون كل خاصية اختيارية ، ولكن يجب عدم السماح للأنواع البدائية الأخرى.
يتطلب Object.observe
هدفًا غير بدائي أيضًا: http://arv.github.io/ecmascript-object-observe/#Object.observe
أعتقد أن العنوان مربك بعض الشيء لأنه يذكر كلمة "بدائي". يمكن بدلاً من ذلك تسمية _ "نوع كائن ECMAScript" _ أو _ "نوع كائن وقت التشغيل" _. والتي يمكن تخصيصها من أي شيء آخر غير الأنواع الأولية (بما في ذلك النوع والرموز undefined
) أو أنواع الوظائف أو المُنشئ. يجب أن تستند معايير نوع object
القانوني إلى الحارس التالي:
let isObject (x) => typeof x === "object";
وفقًا لـ MDN ، هذا هو ناتج typeof
:
غير محدد : "غير محدد"
لاغية : "كائن" (انظر أدناه)
منطقي : "منطقي"
الرقم : "number"
سلسلة : "سلسلة"
الرمز (جديد في ECMAScript 2015) : "الرمز"
الكائن المضيف (توفره بيئة JS) : يعتمد على التنفيذ
كائن الوظيفة (يطبق [[استدعاء]] بمصطلحات ECMA-262 : "function"
أي كائن آخر : "كائن"
بدون هذا النوع ، لا توجد طريقة لمطابقة نوع دقيق للحارس المذكور أعلاه بشكل صحيح ، ولا حتى كحارس معرف من قبل المستخدم. وهذا أمر ضروري للاستخدام مع أي وظيفة أيضا يتطلب بدقة كائن له خصائص ويسمح for in
الحلقات والمكالمات إلى Object
النموذج، ولتنفيذ القيود عامة مثل T extends object
ثم الرجوع إلى الخصائص بأمان أو استخدام وظائف النموذج الأولي.
ومع ذلك ، فإن استبعاد الدوال والمنشئات سيكون محدودًا بعض الشيء في بعض الحالات ، لذلك قد يكون هناك نوع آخر من شأنه أن يشملهم أيضًا ويسمى _ "نوع الكائن غير البدائي" _. قد يكون الحل الجزئي هو الاتحاد object | Function
الرغم من الحاجة إلى استخدام القوالب أو الحراس الإضافيين للتعامل معه بشكل صحيح.
قبول العلاقات العامة. ويبدو أن هذا مشكلة شائعة؛ سيكون هذا تغييرًا جذريًا لأي شخص شجاع بما يكفي لكتابة interface object { ... }
. يجب أن يكون التنفيذ مباشرًا ويتبع القواعد الموضحة أعلاه.
ملاحظة جانبية: نحن جميعًا نتساءل أين كان fdecampredon !
RyanCavanaugh تغيير مدينة العمل ، وللأسف ليس هناك الكثير من الكتابة المطبوعة في وظيفتي الجديدة: D
عظيم. أريد استخدام هذا النوع في TS1.8.
أود أيضًا أن أرى شيئًا مثل نوع object
. ومع ذلك ، أتساءل عما إذا كان يجب أن يتوافق مع typeof value === 'object'
، لأن هذا قد يستبعد الوظائف. بدلاً من ذلك ، يبدو لي أن النوع المرتقب object
يجب أن يعكس نوع لغة الكائن ، الذي يتضمن الوظائف. هناك عدة أسباب لذلك:
Object
.سآخذ هذه بالترتيب.
تقبل واجهات برمجة التطبيقات مثل WeakMap
التي تأخذ الكائنات فقط نوع لغة الكائن ، وليس الكائنات العادية فقط. ما يلي مقبول:
function theAnswer() {}
let map = new WeakMap();
map.set(theAnswer, 42);
console.log(map.get(theAnswer)); // 42
هذا صحيح بالنسبة لواجهات برمجة التطبيقات المخصصة كما هو الحال بالنسبة لواجهات برمجة التطبيقات المضمنة. إذا كنت أتوقع كائنًا ، فأنا عادةً ما أريد فقط مجموعة من الخصائص. الوظائف هي مجرد حزم من الخصائص يمكن استدعاءها.
نظرًا لأن Function
يوسع المُنشئ Object
، يمكننا استخدام الأساليب الثابتة والمثيلات المتاحة في Object
على الوظائف أيضًا. على سبيل المثال ، ما يلي ممكن:
class DeepThought {
static getAnswer() {
return 42;
}
}
let computer = Object.create(DeepThought);
console.log(computer.getAnswer()); // 42
console.log(Object.getPrototypeOf(computer)); // [Function: DeepThought]
على الرغم من أن المثال أعلاه سخيف بعض الشيء ، إلا أنه يوضح فقط أن واجهات برمجة التطبيقات التي تستخدم طرق Object
داخليًا يمكنها قبول الوظائف أيضًا.
لذا أود أن أقترح أن النوع object
يتوافق مع ما يلي ، والذي يتوافق مع نوع لغة الكائن (باستثناء أنها تتضمن null
، لكن لا يوجد أي حماية ضد null
في TypeScript على كل حال).
function isObject(value) {
return typeof value === 'object' || typeof value === 'function';
}
لدي مشروع يسمى Deep Map يتكرر من خلال أزواج القيمة الرئيسية للكائنات المتداخلة ويحول القيم الأولية على طول الطريق. على هذا النحو ، فإنه يميز بين الأنواع البدائية وغير البدائية. اضطررت إلى تحديد واجهة مخصصة NonPrimitive
، على النحو التالي:
interface NonPrimitive {
[key: string]: any;
[index: number]: any;
}
export class DeepMap {
// ...
private mapObject(obj: NonPrimitive): NonPrimitive { /* ... */ }
}
هذه ليست المرة الأولى التي أضطر فيها إلى تحديد واجهة NonPrimitive
. سيكون من الرائع أن أفعل هذا:
export class DeepMap {
// ...
private mapObject(obj: object): object { /* ... */ }
}
كما اقترحت أعلاه ، لا يهمني حقًا ما إذا كانت المعلمة obj
قابلة للاستدعاء أم لا. كل ما يهم هو أنه من النوع Object
_language_ ، أي أنه مجموعة من الخصائص التي يمكنني تكرار أزواج القيمة الرئيسية من خلالها.
أوافق على أن الوظائف هي object
s. القصد هو استبعاد الأوليات.
حسنًا ، اعتقدت أن هذا كان القصد. لقد ظننت أنني ربما أفتقد شيئًا مع كل هذا الحديث عن typeof value === 'object'
.
هل سيسمح هذا النوع object
بتعيين خاصية مخصصة (مثل any
)؟ فمثلا:
const foo: object = {};
foo.bar = 'baz';
لا
ما هو الفرق العملي بين
export class DeepMap {
// ...
private mapObject(obj: object): object { /* ... */ }
}
و
export class DeepMap {
// ...
private mapObject(obj: Object): Object { /* ... */ }
}
؟ (باستخدام object
مقابل Object
). يبدو لي أن Function
يمتد من Object
، لذلك لا أرى سبب عدم قدرتنا على القيام بذلك بالفعل. هل يمكن ان توضح؟
trusktr جميع القيم بخلاف null
و undefined
يمكن تخصيصها للنوع Object
؛ الدالة التي تقبل Object
ستتخذ سلسلة أو رقمًا أو منطقيًا أو رمزًا. يتم object
القيم غير الأولية فقط إلى object
مفيدًا حيث نتوقع قيمة غير أولية ، ولكن عندما لا نهتم بماهية خصائصه.
التعليق الأكثر فائدة
+1 على هذا الاقتراح. لن أعتبر أن
WeakMap
واجهة برمجة تطبيقات "خبير" ، لكنني أعتبرها سببًا كافيًا لتنفيذ ذلك. نظرًا لأن وقت التشغيل يميز بين أنواع الكائنات والأنواع الأولية ، فمن المنطقي أن يكون لديك ميزة في TypeScript لتمييزها أيضًا.سيحل هذا الاقتراح أيضًا مشكلة كتابة "أكياس الكائنات" حيث تكون كل خاصية اختيارية ، ولكن يجب عدم السماح للأنواع البدائية الأخرى.