Typescript: Es ist unmöglich, eine statische 'Längen'-Funktion für eine Klasse zu definieren

Erstellt am 12. Aug. 2014  ·  22Kommentare  ·  Quelle: microsoft/TypeScript

Das folgende Typoskriptprogramm wird akzeptiert:

class C {
    static length ()  { return "twelve"; }
}

Im generierten Code jedoch:

var C = (function () {
    function C() {
    }
    C.length = function () {
        return "twelve";
    };
    return C;
})();

Hier wird versucht, der Eigenschaft length einer Funktion zuzuweisen. Dies funktioniert nicht (zumindest in Firefox und Chrome) und führt dazu, dass nachfolgende Aufrufe von C.length() abstürzen. Vielleicht sollte das Aufrufen einer statischen Klassenfunktion length einfach nicht zugelassen werden?

Migriert von Codeplex- Problem Nr. 1260 .

Bug Fixed good first issue help wanted

Hilfreichster Kommentar

Inzwischen ist der native ES6 / 2015-Support in Chrome und Firefox gelandet. Wenn wir beobachten, wie diese das Problem nativ behandeln, kommt es dem nahe, was @ nicolo-ribaudo und ich vorgeschlagen haben (siehe # 9778).

Snippet zur Veranschaulichung des nativen Verhaltens:

class Foo {
    constructor() {}
}
class Bar {
    static length() {}
    static name() {}
    static caller() {}
}
Foo.name = "FooChanged";
Bar.name = "Baz";

console.log(Foo.name) // Logs "Foo". Foo.name remains unwritable
console.log(Bar.name) // Logs "Baz".  Bar.name became writable

In Bezug auf das, was @tinganho zuvor über die Lesbarkeit von name , length und caller , können wir für die nativen Implementierungen beobachten, dass die Eigenschaften einmal auf eine Konstruktorfunktion geschrieben werden können Wir haben eines dieser Elemente als statisches Klassenmitglied definiert (Sie können meine jüngsten Warnungen zu MDN bezüglich gefährlicher Annahmen über Function.name für das Abrufen eines Klassennamens aus diesem Grund überprüfen oder ändern).

Die Verwendung von Object.defineProperty wie von @ nicolo-ribaudo vorgeschlagen, würde das native Verhalten genau emulieren. Eine Sache, die berücksichtigt werden muss, ist, dass einige ältere, aber ES5-kompatible Browserversionen die Eigenschaften auf configurable: false . Der Versuch, sie zu writable: true , schlägt für sie fehl (siehe z. B. Konfigurierbarkeit von Function.name ).

Zusammenfassend war meine Meinung zu diesem Thema:

  • Wir können Object.defineProperty() für das Kompilierungsziel es3 . Ohne Object.defineProperty Ausführen von ES3-Code in einer ES5-Umgebung jedoch das schreibgeschützte Problem verursachen. Daher benötigen wir einen Kompilierungsfehler für das Ziel es3
  • Kompilieren Sie es mit Object.defineProperty() und writable: true für das Kompilierungsziel es5 und geben Sie eine Warnung / einen Fehler aus, der besagt, dass die Verwendung dieser Eigenschaftsnamen Fehler in Browsern verursachen kann, die x of version <= y vorschlagen Wenn diese Browser unterstützt werden müssen, ist es am sichersten, einen anderen Namen zu wählen.
  • Wenn Sie absolut nicht möchten, dass Benutzer die Eigenschaften verwenden, generieren Sie einen Kompilierungsfehler für beide Ziele.

Unabhängig von der Kompilierungsausgabe denke ich, dass jede Art von zusätzlicher Nachricht besser wäre als die heutige Situation (TS 1.8.10), in der wir überhaupt keinen Hinweis auf mögliche Probleme mit der Compilerausgabe erhalten.

Bearbeiten : Ausgeschnitten hinzugefügt

Alle 22 Kommentare

Ich bin kürzlich darauf gestoßen. :((

Auch einige andere sind nicht zulässig, z. B. sollte der folgende Code fehlerhaft sein (wenn wir diese Funktion ausführen):

class C {
    static name = 'something';
    static arguments = 'args';
    static caller = 'caller';
}

console.log(C.name); // 'C'
console.log(C.arguments); // null
console.log(C.caller); // null

Nicht alle davon sind jedoch Standard.

Ich denke nicht, dass die Eigenschaften name , caller und length machbar sind. Sie sind schreibgeschützt und können nicht überschrieben werden. Alle ihnen zugewiesenen Zuordnungen werden ignoriert.

@tinganho stimmte zu

Ok, aber da die Leute von Zeit zu Zeit solche Fehler bemerken, denke ich, dass TS sie darüber informieren sollte, dass sie etwas falsch gemacht haben. Dies liegt daran, dass Eigenschaften wie name oder length so natürlich sind, dass die Leute versuchen, sie immer wieder neu zu definieren.

Kann sein, weil Lengh, Name bereits definiert sind.

Ich werde versuchen, daran zu arbeiten. Gibt es außer dem, was bereits erwähnt wurde, weitere Eigenschaftsnamen, die nicht zugelassen werden sollten?

Bisher sehe ich:
Länge, Name, Argumente, Anrufer

Was genau sollte passieren, wenn jemand versucht, eine statische Eigenschaft mit einem der verbotenen Namen festzulegen? Compilerfehler? Sichtbare Warnung für den Benutzer?

Ich bin neu in diesem Bereich. Wenn mir also etwas fehlt, wäre eine Anleitung willkommen. : +1:

Warum nicht kompilieren?

class C {
    static name = 'something';
    static arguments = 'args';
    static caller = 'caller';
}

console.log(C.name); // 'C'
console.log(C.arguments); // null
console.log(C.caller); // null

zu so etwas wie

var C = (function () {
    function C() {
    }

    C.__statics = {
        name: 'something',
        arguments: 'args',
        caller: 'caller'
    };

    return C;
})();
console.log(C.__statics.name); // 'something'
console.log(C.__statics.arguments); // 'args'
console.log(C.__statics.caller); // 'caller'

Die Frage wurde auch zu stackoverflow gestellt: http://stackoverflow.com/a/34644236/390330 : rose:

@zerkms bitte

Sie können Namen in einem strukturellen Typsystem manchmal nicht willkürlich umschreiben.

Betrachten Sie einen Code wie diesen

interface HasName {
  name: string;
}
class Foo {
  static name = 'fooClass';
}
let bar: HasName = { name: string };
let q = Math.random() > 0.5 ? Foo : bar;
console.log(q.name);

@ RyanCavanaugh , das ist in der Tat ein faires Beispiel (ich entwickle nicht auf TS, aber

Wenn es nicht möglich ist, sie ohne Risiko zu transpilieren, sollten wir sie vielleicht einfach verbieten?

Wenn es nicht möglich ist, sie ohne Risiko zu transpilieren, sollten wir sie vielleicht einfach verbieten?

Das Transpile definitiv nicht ändern, sondern nur zu einem Kompilierungsfehler machen: rose:

[...] vielleicht sollten wir sie einfach verbieten?

Einige unternehmungslustige Entwickler sollten uns eine PR schicken! :zwinkern:

Warum nicht Object.defineProperty ?

z.B

class C {
    static length() { return "twelve"; }
}

würde auf so etwas übertragen werden

var C = (function () {
    function C() {
    }
    Object.defineProperty(C, "length", {
        value: function () { return "twelve"; },
        writable: true
    });
    return C;
}());

@ nicolo-ribaudo Das funktioniert ja. Meine Meinung: aber ich würde lieber einen Fehler sehen als eine solche Transpile. TypeScript stützt sich im Allgemeinen auf die Seite des anmutigen Fehlers, anstatt JavaScript zu reparieren: rose:

TypeScript stützt sich im Allgemeinen auf die Seite eines schwerwiegenden Fehlers, anstatt JavaScript zu reparieren

Ist nicht die ganze Idee von TS, das JS zu reparieren, indem die Lücken gefüllt werden, die es nicht kann und wird.

Ist nicht die ganze Idee von TS, das JS zu reparieren, indem die Lücken gefüllt werden, die es nicht kann und wird.

Ja. Aber wenn Sie verstehen, wie JavaScript funktioniert. Nehmen Sie ein Beispiel für null und undefined . TypeScript möchte beides verstehen (anstatt es wie Dart zu einer einzigen Sache zu konsolidieren, tut https://www.dartlang.org/docs/synonyms/). TypeScript gibt Fehler aus (anstatt sie im Transpile zu beheben), wenn Sie das falsche JavaScript-Muster verwenden: rose:

Meine Meinungen sind meine eigenen und werden von niemandem außer mir gebilligt: ​​rose:

Inzwischen ist der native ES6 / 2015-Support in Chrome und Firefox gelandet. Wenn wir beobachten, wie diese das Problem nativ behandeln, kommt es dem nahe, was @ nicolo-ribaudo und ich vorgeschlagen haben (siehe # 9778).

Snippet zur Veranschaulichung des nativen Verhaltens:

class Foo {
    constructor() {}
}
class Bar {
    static length() {}
    static name() {}
    static caller() {}
}
Foo.name = "FooChanged";
Bar.name = "Baz";

console.log(Foo.name) // Logs "Foo". Foo.name remains unwritable
console.log(Bar.name) // Logs "Baz".  Bar.name became writable

In Bezug auf das, was @tinganho zuvor über die Lesbarkeit von name , length und caller , können wir für die nativen Implementierungen beobachten, dass die Eigenschaften einmal auf eine Konstruktorfunktion geschrieben werden können Wir haben eines dieser Elemente als statisches Klassenmitglied definiert (Sie können meine jüngsten Warnungen zu MDN bezüglich gefährlicher Annahmen über Function.name für das Abrufen eines Klassennamens aus diesem Grund überprüfen oder ändern).

Die Verwendung von Object.defineProperty wie von @ nicolo-ribaudo vorgeschlagen, würde das native Verhalten genau emulieren. Eine Sache, die berücksichtigt werden muss, ist, dass einige ältere, aber ES5-kompatible Browserversionen die Eigenschaften auf configurable: false . Der Versuch, sie zu writable: true , schlägt für sie fehl (siehe z. B. Konfigurierbarkeit von Function.name ).

Zusammenfassend war meine Meinung zu diesem Thema:

  • Wir können Object.defineProperty() für das Kompilierungsziel es3 . Ohne Object.defineProperty Ausführen von ES3-Code in einer ES5-Umgebung jedoch das schreibgeschützte Problem verursachen. Daher benötigen wir einen Kompilierungsfehler für das Ziel es3
  • Kompilieren Sie es mit Object.defineProperty() und writable: true für das Kompilierungsziel es5 und geben Sie eine Warnung / einen Fehler aus, der besagt, dass die Verwendung dieser Eigenschaftsnamen Fehler in Browsern verursachen kann, die x of version <= y vorschlagen Wenn diese Browser unterstützt werden müssen, ist es am sichersten, einen anderen Namen zu wählen.
  • Wenn Sie absolut nicht möchten, dass Benutzer die Eigenschaften verwenden, generieren Sie einen Kompilierungsfehler für beide Ziele.

Unabhängig von der Kompilierungsausgabe denke ich, dass jede Art von zusätzlicher Nachricht besser wäre als die heutige Situation (TS 1.8.10), in der wir überhaupt keinen Hinweis auf mögliche Probleme mit der Compilerausgabe erhalten.

Bearbeiten : Ausgeschnitten hinzugefügt

@ RyanCavanaugh :

Die Tags in der PR zeigen an, dass das TypeScript-Team, das nur über begrenzte Ressourcen verfügt, dies der Community zur Adressierung überlässt. Wenn Sie dieses Problem beheben möchten, muss es jemand in der breiteren Community angehen, bis das TypeScript-Kernteam das Gefühl hat, im Backlog genügend Platz zu haben, um es in eine Version aufzunehmen (was wahrscheinlich eine lange, lange Zeit in Anspruch nehmen würde).

@kitsonk Vielen Dank für die Erklärung des PR-Labels. Ich glaube ich habe das verstanden. Was ich vorgeschlagen habe, war eine Neubewertung, ob es immer noch der richtige Weg ist, um das Problem zu lösen. Es ist nicht so unwahrscheinlich, dass statische Klasseneigenschaften mit den Namen _name_ oder _length_ auftreten, und TS erzeugt dafür eine fehlerhafte Ausgabe. Daher würde ich das Problem und den "Randfall" nicht einmal nennen.

Ich halte statische Eigenschaften für das Kernstück der Sprache, und selbst wenn noch keine Pull-Anforderungen vorhanden sind, wurden in diesem Thread Lösungen für das Problem vorgestellt.

Trotzdem werde ich prüfen, ob ich eine PR bereitstellen kann, aber ich muss zugeben, dass ich mich noch nicht so gut mit TS-Quellen auskenne und befürchte, dass TS 2.0 zuvor veröffentlicht wird.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen