Typescript: Tidak mungkin untuk mendefinisikan fungsi 'panjang' statis di kelas

Dibuat pada 12 Agu 2014  ·  22Komentar  ·  Sumber: microsoft/TypeScript

Program naskah ketikan berikut diterima:

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

Namun, dalam kode yang dihasilkan:

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

Di sini, upaya dilakukan untuk menetapkan ke properti length dari suatu fungsi. Ini tidak berfungsi (setidaknya di Firefox dan Chrome), menyebabkan panggilan C.length() macet. Mungkin memanggil fungsi kelas statis length seharusnya tidak diizinkan?

Bermigrasi dari masalah codeplex

Bug Fixed good first issue help wanted

Komentar yang paling membantu

Sementara itu, dukungan asli ES6 / 2015 telah mendarat di Chrome dan Firefox. Jika kita mengamati bagaimana ini menangani masalah secara asli maka itu mendekati apa yang @ nicolo-ribaudo dan saya usulkan (lihat # 9778).

Cuplikan untuk menggambarkan perilaku asli:

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

Sehubungan dengan apa yang telah ditulis @tinganho sebelumnya tentang name , length dan caller kita dapat mengamati implementasi asli bahwa properti dapat ditulis pada fungsi konstruktor sekali kami telah mendefinisikan salah satu dari mereka sebagai anggota kelas statis (silakan meninjau atau memodifikasi peringatan saya baru ini di MDN mengenai asumsi berbahaya tentang Function.name untuk mendapatkan nama kelas, karena ini).

Jadi menggunakan Object.defineProperty seperti yang disarankan oleh @ nicolo-ribaudo akan meniru perilaku asli secara akurat. Satu hal yang perlu dipertimbangkan adalah bahwa beberapa versi browser yang lebih tua tetapi kompatibel dengan ES5 telah menetapkan propertinya menjadi configurable: false . Jadi mencoba membuatnya writable: true akan gagal untuk mereka (misalnya lihat konfigurasi Function.name )

Singkatnya, pendapat saya tentang masalah ini adalah:

  • Kami tidak dapat menggunakan Object.defineProperty() untuk target-kompilasi es3 . Tanpa Object.defineProperty , menjalankan kode ES3 di lingkungan ES5, bagaimanapun, akan menemui masalah read-only. Oleh karena itu kita membutuhkan kesalahan kompilasi untuk target es3
  • kompilasi dengan Object.defineProperty() dan writable: true untuk compile-target es5 dan berikan peringatan / kesalahan yang menyatakan bahwa menggunakan nama properti ini dapat menyebabkan kesalahan di browser x of version <= y menyarankan bahwa, jika browser ini harus didukung, opsi teraman adalah memilih nama lain.
  • jika Anda benar-benar tidak ingin orang menggunakan properti, buat kesalahan kompilasi untuk salah satu target.

Terlepas dari keluaran kompilasi, saya pikir semua jenis pesan tambahan akan lebih baik daripada bagaimana situasinya saat ini (TS 1.8.10) di mana kita tidak mendapatkan petunjuk sama sekali tentang potensi masalah dengan keluaran kompilator.

Edit : Potongan ditambahkan

Semua 22 komentar

Saya mengalami ini baru-baru ini. :(

Juga beberapa lainnya tidak diperbolehkan misalnya kode berikut harus error (jika kita melakukan fitur ini):

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

Namun tidak semua ini adalah standar.

Saya tidak berpikir properti name , caller dan length bisa dilakukan. Properti tersebut adalah properti hanya baca dan tidak dapat diganti. Semua penugasan kepada mereka akan diabaikan.

@tinganho setuju

Oke, tetapi karena orang-orang menangkap kesalahan semacam ini dari waktu ke waktu, saya pikir TS harus memberi tahu mereka tentang melakukan sesuatu yang salah. Itu karena properti seperti name atau length begitu wajar untuk diingat sehingga orang akan mencoba mendefinisikannya lagi dan lagi.

Mungkin karena Lengh, Namanya Sudah Didefinisikan.

Saya akan mencoba dan mengerjakan ini. Selain dari apa yang telah disebutkan, apakah ada nama properti lain yang tidak boleh diizinkan?

Sejauh ini saya melihat:
panjang, nama, argumen, pemanggil

Apa yang seharusnya terjadi jika seseorang mencoba menyetel properti statis dengan salah satu nama terlarang? Kesalahan penyusun? Peringatan yang terlihat bagi pengguna?

Saya baru dalam hal ini jadi jika saya melewatkan sesuatu, maka beberapa panduan akan sangat kami hargai. : +1:

Mengapa tidak dikompilasi

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

menjadi sesuatu seperti

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'

Pertanyaan muncul di stackoverflow juga: http://stackoverflow.com/a/34644236/390330 : rose:

@zerkms tolong jangan posting komentar yang sama di dua tempat; ini membingungkan.

Terkadang Anda tidak dapat secara sewenang-wenang menulis ulang nama dalam sistem tipe struktural.

Pertimbangkan beberapa kode seperti ini

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 itu adalah contoh yang adil, memang (saya tidak mengembangkan di TS, tapi astaga - sistem tipenya aneh segera setelah memperlakukan kode ini sebagai valid).

Jika tidak mungkin untuk memindahkannya tanpa risiko, mungkin kita harus melarangnya?

Jika tidak mungkin untuk memindahkannya tanpa risiko, mungkin kita harus melarangnya?

Jelas tidak mengubah transpile, hanya membuatnya menjadi kesalahan kompilasi: rose:

[...] mungkin kita harus melarang mereka?

Beberapa pengembang yang giat harus mengirimkan PR kepada kami! :mengedipkan:

Mengapa tidak menggunakan Object.defineProperty ?

misalnya

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

akan ditranslasikan menjadi sesuatu seperti

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

@ nicolo-ribaudo Itu memang berhasil. Pendapat saya: tapi saya lebih suka melihat kesalahan daripada transparan seperti itu. TypeScript umumnya bersandar pada kesalahan anggun alih-alih _memperbaiki JavaScript_: mawar:

TypeScript umumnya bersandar pada kesalahan anggun alih-alih memperbaiki JavaScript

Bukankah ide keseluruhan TS adalah untuk memperbaiki JS dengan mengisi celah yang tidak bisa dan tidak akan pernah bisa.

Bukankah ide keseluruhan TS adalah untuk memperbaiki JS dengan mengisi celah yang tidak bisa dan tidak akan pernah bisa.

Iya. Tetapi dengan memahami cara kerja JavaScript. Ambil contoh null dan undefined . TypeScript memilih untuk memahami keduanya (alih-alih menggabungkannya menjadi satu hal seperti yang dilakukan Dart https://www.dartlang.org/docs/synonim/). TypeScript memberikan kesalahan (bukan memperbaikinya dalam transpile) jika Anda menggunakan pola JavaScript yang salah: rose:

Pendapat saya adalah milik saya sendiri dan tidak didukung oleh siapa pun kecuali saya: mawar:

Sementara itu, dukungan asli ES6 / 2015 telah mendarat di Chrome dan Firefox. Jika kita mengamati bagaimana ini menangani masalah secara asli maka itu mendekati apa yang @ nicolo-ribaudo dan saya usulkan (lihat # 9778).

Cuplikan untuk menggambarkan perilaku asli:

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

Sehubungan dengan apa yang telah ditulis @tinganho sebelumnya tentang name , length dan caller kita dapat mengamati implementasi asli bahwa properti dapat ditulis pada fungsi konstruktor sekali kami telah mendefinisikan salah satu dari mereka sebagai anggota kelas statis (silakan meninjau atau memodifikasi peringatan saya baru ini di MDN mengenai asumsi berbahaya tentang Function.name untuk mendapatkan nama kelas, karena ini).

Jadi menggunakan Object.defineProperty seperti yang disarankan oleh @ nicolo-ribaudo akan meniru perilaku asli secara akurat. Satu hal yang perlu dipertimbangkan adalah bahwa beberapa versi browser yang lebih tua tetapi kompatibel dengan ES5 telah menetapkan propertinya menjadi configurable: false . Jadi mencoba membuatnya writable: true akan gagal untuk mereka (misalnya lihat konfigurasi Function.name )

Singkatnya, pendapat saya tentang masalah ini adalah:

  • Kami tidak dapat menggunakan Object.defineProperty() untuk target-kompilasi es3 . Tanpa Object.defineProperty , menjalankan kode ES3 di lingkungan ES5, bagaimanapun, akan menemui masalah read-only. Oleh karena itu kita membutuhkan kesalahan kompilasi untuk target es3
  • kompilasi dengan Object.defineProperty() dan writable: true untuk compile-target es5 dan berikan peringatan / kesalahan yang menyatakan bahwa menggunakan nama properti ini dapat menyebabkan kesalahan di browser x of version <= y menyarankan bahwa, jika browser ini harus didukung, opsi teraman adalah memilih nama lain.
  • jika Anda benar-benar tidak ingin orang menggunakan properti, buat kesalahan kompilasi untuk salah satu target.

Terlepas dari keluaran kompilasi, saya pikir semua jenis pesan tambahan akan lebih baik daripada bagaimana situasinya saat ini (TS 1.8.10) di mana kita tidak mendapatkan petunjuk sama sekali tentang potensi masalah dengan keluaran kompilator.

Edit : Potongan ditambahkan

@RyanCavanaugh : bisakah Anda meninjau kembali masalah ini untuk pencapaian TS 2.0.1. Solusi tampaknya lurus ke depan tetapi tergantung pada opsi mana yang Anda pilih, keluaran emitor mungkin perlu diubah (lihat komentar saya sebelumnya). Rilis TS 2.0 mungkin yang terbaik untuk menyertakan perbaikan.

Tag pada PR menunjukkan bahwa tim TypeScript, yang memiliki sumber daya terbatas, membiarkan ini terbuka untuk ditangani oleh komunitas. Jika Anda ingin masalah ini diatasi, seseorang di komunitas yang lebih luas harus menanganinya sampai tim inti TypeScript merasa mereka memiliki cukup ruang di backlog untuk memasukkannya ke dalam rilis (yang kemungkinan akan memakan waktu lama).

@kitsonk Terima kasih telah menjelaskan label PR. Saya pikir saya mengerti itu. Yang saya sarankan adalah mengevaluasi kembali apakah ini masih cara yang tepat untuk menangani masalah tersebut. Properti kelas statis yang disebut _name_ atau _length_ tidak terlalu mungkin terjadi dan TS menghasilkan keluaran yang keliru untuk itu. Oleh karena itu saya bahkan tidak akan menyebut masalah dan "kasus tepi".

Saya menganggap properti statis sebagai inti dari bahasa dan bahkan jika belum ada permintaan tarik, solusi untuk masalah ini telah disajikan di utas ini.

Namun demikian, saya akan mengevaluasi apakah saya dapat memberikan PR tetapi saya harus mengakui bahwa saya belum memiliki pengetahuan tentang sumber TS dan saya khawatir TS 2.0 akan dirilis sebelumnya.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat