Typescript: لا يمكن تمديد الأنواع المضمنة

تم إنشاؤها على ١٤ نوفمبر ٢٠١٤  ·  14تعليقات  ·  مصدر: microsoft/TypeScript

يعيّن ES6 بعض الكائنات الأصلية كفئة فرعية ، على سبيل المثال ، كائن ، منطقي ، خطأ ، خريطة ، وعد .. إلخ. الطريقة التي يتم بها نمذجة هذه البنى في lib.d.ts تجعل من المستحيل تصنيفها إلى فئة فرعية ، حيث يتم تعريفها على أنها زوج من var وواجهة.

من قسم المواصفات ES6 19.5.1:

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

سيؤدي هذا حاليًا إلى ظهور خطأ "يمكن للفئة أن توسع فئة أخرى فقط":

class NotImplementedError extends Error {
    constructor() {
        super("Not Implemented");
    }
}
Bug ES6 Fixed

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

حتى أن هناك إمكانية لتوسيع فئة Error الأيام ، ما زلت أواجه إزعاجًا في العقدة. على سبيل المثال ، أواجه مشكلات مع "error.stack". عندما أحصل على throw new Error(...) أحصل على error.stack ، لكن عندما أحصل على throw new CustomError() - لا أفعل. لحلها أجبرت على استخدام هذه الحيلة:

export class HttpError extends Error {
    httpCode: number;
    message: string;

    constructor(httpCode: number, message?: string) {
        super();
        if (httpCode)
            this.httpCode = httpCode;
        if (message)
            this.message = message;

        this.stack = new Error().stack;
    }
}

ال 14 كومينتر

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

أود أن أقول

class Error;

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

بالنسبة للحالة العامة ، أود أن أتمكن من استبدال نص أي إعلان فئة بفاصلة منقوطة ، مع السماح بأشياء مثل

class Foo<X, Y> extends Bar<X> implements Baz<Y>;

مما يعني أن المكتبة تضمن بالفعل أن Foo.prototype هو مثيل لـ Bar.prototype ويقوم بتنفيذ واجهة Baz.

metaweta @ أعتقد أنه قد يحدث بعض التكرار:

interface Foo {
}
class Foo; // Foo is now a class!
interface Bar extends Foo {
}
class Bar extends Foo; // Two `extends Foo`s. 

interface X {
}
class X extends Foo; // Hmm?
interface Y extends Foo {
}
class Y; // Hmm?

لا يزال لديها بعض الإمكانات لأن الواجهات ذات التصنيف الفرعي ستعمل كصفوف مفتوحة. # 819

metaweta يجب التعامل مع قضيتك الأولى من خلال إعلان فئة البيئة المحيطة. على سبيل المثال

// myLib.d.ts
declare class Error {
}
// no code emitted here for this. 
// myfile.ts
// Error is subclassable,
class MyError extends Error {
}

بالنسبة للحالة الثانية ، أود تقديم مشكلة اقتراح مختلفة لها.

فيما يلي القائمة الكاملة للكائنات "ذات التصنيف الفرعي" من مواصفات ES6. حاليًا يتم تعريف كل هذه على أنها أزواج واجهة / var.

  • موضوع
  • قيمة منطقية
  • خطأ
  • NativeError. خطأ أصلي
  • رقم
  • تاريخ
  • خيط
  • RegExp
  • مجموعة مصفوفة
  • TypedArray (Int8Array و Uint8Array و Int16Array و Uint16Array و Int32Array و Uint32Array و Float32Array و Float64Array و DataView)
  • خريطة
  • جلس
  • خريطة ضعيفة
  • WeakSet
  • ArrayBuffer
  • عرض البيانات
  • وعد

مشاكل:

  • بمجرد تعريف النوع على أنه فئة ، لا توجد طريقة لتوسيع جانب العضو (يمكن أن يحدث توسيع الجانب الثابت من خلال وحدة نمطية).
  • لن تعمل الامتدادات الحالية لجانب العضو حيث لا يمكنك إعادة تعريف فئة (كسر التغيير)
  • لا توجد طريقة لنمذجة استدعاءات الوظائف على فئة ، على سبيل المثال Object و String و Boolean و Date و Number و RegExp و Error و Array. (كسر التغيير مرة أخرى)

الحلول الممكنة:

  • السماح بتوسيع أي نوع بخاصية النموذج الأولي وتوقيع الإنشاء
  • السماح بتمديد جانب المثيل للفئة (على سبيل المثال ، الوحدة النمطية Class.prototype {} ، مقدمة من RyanCavanaugh )
  • السماح بتعريف تواقيع الاتصال على منشئ الفئة

mhegazy شكرًا ، لم أكن على دراية ببناء إعلان الطبقة المحيطة.

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

declare class Error {
  constructor(message?: string);
}

class ExtendedError extends Error {
  constructor(message?: string) {
    super(message + " extended");
  }
}

//throw new Error("Test");
throw new ExtendedError("Test");

unional هذا يبدو وكأنه مشكلة في المحرك. يجب أن يعمل وفقًا لمواصفات ES6. يجب أن تصلح المحركات هذه الآن بعد أن تم التصديق على ES6.

تمكنت من جعله يعمل. في كود js الذي كان يعمل ، لدي استدعاء Error.captureStackTrace ولكني أخرجه عندما أقوم بتطبيقه في ts لأن إعلان الخطأ لا يحتوي عليه.

يوجد مثال على الكود:
إنه استثناء يشبه C # يأخذ استثناءً داخليًا.

declare class Error {
    public name:string;
    public message:string;
    public stack:string;
    constructor(message?:string);
    static captureStackTrace(error: Error, constructorOpt: any);
}

class Exception extends Error {
    public innerException: Error;
    constructor(message?: string, innerException?: Error|string) {
        // Guard against throw Exception(...) usage.
        if (!(this instanceof Exception)) return new Exception(message, innerException);
        super();
        if (typeof Error.captureStackTrace === 'function') {
            //noinspection JSUnresolvedFunction
            Error.captureStackTrace(this, arguments.callee);
        }
        this.name = "Exception";
        if (innerException) {
            if (innerException instanceof Error) {
                this.innerException = innerException;
                this.message = message + ", innerException: " + this.innerException.message;
            }
            else if (typeof innerException === "string") {
                this.innerException = new Error(innerException);
                this.message = message + ", innerException: " + this.innerException.message;
            }
            else {
                this.innerException = innerException;
                this.message = message + ", innerException: " + this.innerException;
            }
        }
        else {
            this.message = message;
        }
    }
}

تم الإصلاح بواسطة # 3516. يمكن للفئات الآن توسيع التعبيرات العشوائية لأنواع دالة المنشئ.

ما هو إصدار TypeScript الذي سيتم شحن هذا الإصلاح؟
لقد تحققت بسرعة من ملصقات الإصدار لـ 1.5.3 و 1.5.4 ، ويبدو أنه لم يتم شحنها بعد ، فقط في الإصدار الرئيسي في الوقت الحالي.

تعديل:
عذرًا ، لقد لاحظنا الآن أن الخطأ تم تمييزه بواسطة المعلم الرئيسي "TypeScript 1.6"

شكرا لعملكم!

kostrse يمكنك تجربة إصداراتنا الليلية من TypeScript 1.6 من خلال تشغيل npm install -g typescript@next .

مرحبا،

أنا أستخدم Typescript 1.6.2 ويظهر lib.es6.d.ts الخاص بي خطأ (و Array، ...) كواجهة وليس فئة.
هل هذا ثابت بالفعل في 1.6.2؟

في صحتك!

jpsfs الإصلاح ، كما أشار ahejlsberg في https://github.com/Microsoft/TypeScript/issues/1168#issuecomment -112955503 هو السماح للفئات بتوسيع التعبيرات العشوائية لأنواع وظائف المُنشئ.

حتى أن هناك إمكانية لتوسيع فئة Error الأيام ، ما زلت أواجه إزعاجًا في العقدة. على سبيل المثال ، أواجه مشكلات مع "error.stack". عندما أحصل على throw new Error(...) أحصل على error.stack ، لكن عندما أحصل على throw new CustomError() - لا أفعل. لحلها أجبرت على استخدام هذه الحيلة:

export class HttpError extends Error {
    httpCode: number;
    message: string;

    constructor(httpCode: number, message?: string) {
        super();
        if (httpCode)
            this.httpCode = httpCode;
        if (message)
            this.message = message;

        this.stack = new Error().stack;
    }
}
هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

Antony-Jones picture Antony-Jones  ·  3تعليقات

DanielRosenwasser picture DanielRosenwasser  ·  3تعليقات

uber5001 picture uber5001  ·  3تعليقات

jbondc picture jbondc  ·  3تعليقات

blendsdk picture blendsdk  ·  3تعليقات