Typescript: Pengubah akses berbeda untuk pengambil dan penyetel

Dibuat pada 21 Apr 2015  ·  40Komentar  ·  Sumber: microsoft/TypeScript

Mungkinkah mengimplementasikan pengubah akses yang berbeda untuk pengambil dan penyetel? Dengan cara ini, setter dapat berupa private/protected dan getter public. Dalam beberapa kasus, ini sangat berguna ketika nilainya hanya-baca.

Contoh:

class MyClass {
    private _myProp: any;
    private set myProp(value: any) {
        this._myProp = value;
    }
    public get myProp(): any {
        return this._myProp;
    }
}
Declined Suggestion Too Complex

Komentar yang paling membantu

Pokoknya tambahkan +1 saya untuk ini, kalau-kalau dipertimbangkan lagi di masa mendatang ...

Semua 40 komentar

12

Karena #12 ditutup dengan #6532 sekarang tampaknya masalah ini di luar cakupan.
Apakah Anda sekarang memiliki rencana untuk menerapkan pengubah akses yang berbeda?
Karena readonly tidak cukup untuk menyelesaikan apa yang dijelaskan di sini sebagai properti mungkin sebenarnya dapat ditulis di dalam kelas.

Saya yakin saya juga harus memindahkan contoh saya ke sini dari masalah terkait:

declare abstract class Emitter {
    new (): Emitter;
    on: (name:string, handler: (arg:any) => void) => void;
    off: (name:string, handler: (arg:any) => void) => void;
    protected emit: (name:string, arg:any) => void;
}

class Person extends Emitter {
    constructor(name:string) {
        super();
        this.name = name;
    }

    private _name:string;
    get name() {
        return this._name;
    }
    set name(value) {
        if (this._name !== value) {
            this._name = value;
            this.emit('change:name', value);
            //this way is better
            this.updatedAt = new Date();
            //than this way
            this.setUpdatedAt(new Date());
        }
    }

    ////
    private _updatedAt:Date;
    get updatedAt() {
        return this._updatedAt;
    }
    private set updatedAt(value) { //Getter and setter do not agree in visibility
                //some logic and a simple readonly (our absence of a setter) is not enough
        if (this._updatedAt !== value) {
            this._updatedAt = value;
            this.emit('change:updatedAt', value);
        }
    }

    //// method implementation - but what's the point in it?
    private setUpdatedAt(value) {
        if (this._updatedAt !== value) {
            this._updatedAt = value;
            this.emit('change:updatedAt', value);
        }
    }
}

const entity = new Person('Mike');
entity.on('change:updatedAt', console.log.bind(console));
entity.name = 'Thomas';
//but manually setting updatedAt should be forbidden
entity.updatedAt = new Date(); //restricted

Di sini, properti updatedAt sebenarnya dapat memiliki setter tetapi tidak dapat diakses di luar Person . Selain itu setter ini berisi logika yang kompleks dan readonly sederhana atau tidak adanya setter tidak cukup.

Saya setuju bahwa setter pribadi hanyalah gula sintaks untuk metode pribadi dengan logika tambahan (seperti memancarkan) tetapi saya pikir itu tidak konsisten ketika bagian dari logika yang terkait dengan bidang ada di properti (pengambil) dan yang lain dalam metode (penyetel pribadi) .

Dengan cara ini getter/setter diimplementasikan dalam C# , saya pikir akan berguna untuk memungkinkan visibilitas yang berbeda pada waktu kompilasi, meskipun kontrak ini akan hilang saat runtime.

Rekomendasi di sini adalah menggunakan pengambil hanya-baca publik dan bidang dukungan pribadi/dilindungi.

Accessor simetris dengan properti dalam sistem tipe. apa pun yang kita lakukan perlu dimanifestasikan dalam jenis dan dapat diekspresikan pada properti. Menambahkan pengubah akses baru untuk mengaktifkan private_set/public_get akan meningkatkan kompleksitas bahasa dan kurva pembelajaran, dan nilai yang diperoleh dari ini tidak akan cocok dengan kompleksitas tambahan.

Pokoknya tambahkan +1 saya untuk ini, kalau-kalau dipertimbangkan lagi di masa mendatang ...

Saya masih ingin melihat ini. C# memilikinya, dan ini sangat berguna dalam banyak keadaan, terutama ketika Anda memiliki flag yang ingin dibaca secara eksternal ke kelas, tetapi hanya disetel secara internal dengan private/protected.

Saya pikir saran bahwa itu tidak sering digunakan adalah lelucon karena polanya tidak digunakan karena tidak tersedia untuk digunakan.

Ini adalah tambahan yang bagus untuk bahasa ini: Jumlah kerumitan yang akan ditambahkan ini (dari perspektif programmer TypeScript) kecil. Konsepnya mudah dipahami dan kompiler harus dapat memberikan pesan kesalahan yang baik yang mengisyaratkan mengapa Anda tidak dapat mengakses getter atau setter karena pelingkupan.

Saya setuju dengan pengguna di atas, ini standar untuk sebagian besar bahasa lain. Argumen yang menentangnya tidak memiliki bobot dan implementasinya harus dipertimbangkan kembali.

Saya sebenarnya terkejut Anda tidak dapat melakukan ini di TS ... +1 untuk masalah ini.
Seharusnya tidak ada peningkatan kurva belajar dengan ini

private get x() { ... }
public set x(value) { ... }

Imo jika Anda dapat membaca bahasa Inggris, cukup jelas apa yang dimaksud dengan private(protected)/public di sini. Juga jika Anda mendefinisikan pengakses di tempat pertama - Anda mungkin sudah tahu untuk apa mereka.

Ps Tentang kesalahan: "Akses pengambil dan penyetel tidak setuju dalam visibilitas" - yah: itulah yang saya ingin mereka lakukan

Berikut adalah dua kasus penggunaan di mana ini akan berguna:

Backbone.js, untuk menghindari panggilan .get() dan .set() yang jelek:

class Whatever {
    public get rotation(): number {
        return this.get('rotation');
    }
    private set rotation(rotation: number) {
        this.set('rotation', rotation);
    }
}

Properti yang dapat dimodifikasi oleh subkelas:

class ExtendMe {
    public get someProperty(): string {
        // some stuff
    }
    protected set someProperty(prop: string) {
        // some stuff
    }
}

Saya pasti ingin melihat ini, karena telah mengganggu saya sejak saya mulai menggunakan TypeScript.

Saya setuju dengan orang-orang yang meminta fitur ini. Saya baru saja mencoba memiliki metode get() publik dan terkejut melihat bahwa set dan get saya harus menyetujui visibilitas.

Saya telah membaca kalian mengklaim itu terlalu rumit. Mengingat "C++ cara" mengapa berbeda dari:

private _myAttribute: string;
get myAttribute(): string {...}
setMyAttribute(value: string) {...}

Saya dapat melihat banyak kasus penggunaan untuk ini, itu sebabnya saya di sini sekarang.
Bagaimana jika saya ingin myAttribute dapat diakses publik tetapi hanya mengizinkan untuk dimodifikasi di dalam kelasnya?
Bagaimana jika saya ingin menambahkan beberapa logika khusus setiap kali atribut diubah?
Ini bisa menjadi aturan bisnis, bisa juga hanya logging untuk memahami mengapa itu telah diberi nilai tertentu, bersama dengan kondisi breakpoint untuk tujuan debugging, dll...

Pada dasarnya, kami ingin metode digunakan setiap kali kami memodifikasi atribut bersama dengan gula sintaksis yang membuatnya tampak seperti kami hanya menetapkan nilai, daripada memanggil metode.
C# memiliki konsep properti untuk ini dan saya pikir TS mewarisi konsep itu, tetapi tidak mengizinkan aksesibilitas yang berbeda adalah batasan besar bagi orang-orang yang berpikir seperti saya dan membuat kita kembali ke "gaya C++".

"Terlalu sulit" seharusnya tidak pernah menjadi alasan untuk tidak mengimplementasikan fitur yang sangat berguna.

Menambahkan +1 saya. Tampaknya sangat aneh bagi saya bahwa dalam bahasa yang begitu lengkap dalam banyak hal Anda tidak dapat melakukan ini.

Terkejut menemukan bahwa masalah ini ditandai sebagai ditutup. Fitur ini DIINGINKAN oleh komunitas. Silakan buka kembali.
+1

12 tidak membahas masalah ini, jadi masalah ini tidak boleh ditutup dengan komentar yang mengacu pada masalah itu.

IMHO ini adalah fitur yang bagus tetapi seadil yang saya mengerti itu hanya situasinya "well, saya TIDAK ingin menulis setiap kali _property alih-alih saya ingin menggunakan properti set pribadi"

Jika ada pilihan untuk menambahkan kompleksitas besar ke kode inti TypeScript itu sendiri (ingat, lebih banyak kompleksitas yang tidak perlu - lebih sedikit kecepatan mengembangkan sesuatu, lebih banyak waktu untuk men-debug, menulis tes, pada akhirnya - rilis lebih jarang) tetapi mengurangi penulisan 1 simbol ATAU penulisan 1 simbol itu dan tangani dengan baik... Saya lebih suka menulis 1 simbol sekali lagi setiap waktu. Pada akhirnya, saya bukan kontributor inti TS dan saya pasti tidak ingin berurusan dengan kemungkinan kerumitan gula ini.

Ini bukan dealbreaker guys. Juga dibutuhkan keberanian dan kebijaksanaan untuk menganggap permintaan terlalu rumit untuk diterapkan (dengan hasil meningkatkan kompleksitas kode secara keseluruhan), jadi angkat topi untuk kalian yang mengembangkan TypeScript dan terima kasih atas pekerjaan Anda!

(ps datang ke sini untuk mempelajari mengapa tidak - pada akhirnya berubah pikiran dan akan menangani ini._property = ...
dan akan tetap bahagia)

@idchlife Tujuan properti set bukanlah untuk menyelamatkan pengembang satu garis bawah saat menetapkan nilai. Anda juga mungkin ingin menambahkan beberapa logika dalam proses set .

Silakan buka kembali masalah ini. Ini jelas merupakan fitur yang sangat diinginkan.

+1 Saya ingin melihat ini dipertimbangkan kembali.

Sangat aneh alasan Anda adalah "ini akan membuat segalanya membingungkan" ketika banyak bahasa lain sudah melakukan ini.

Karena semua 👍 tidak melakukan banyak hal, saya hanya akan mengirim spam dengan satu komentar 👍 lagi.

Ini akan menjadi gula sintaksis yang membantu membuat segalanya lebih mudah dibaca dan cepat diimplementasikan. Banyak bahasa memiliki gula sintaksis termasuk TypeScript. Sepertinya tidak ada alasan bagus untuk tidak melakukannya dan terlalu rumit tidak pernah menjadi alasan yang baik untuk tidak melakukan sesuatu, itu lebih merupakan tindakan malas. Memecahkan masalah yang terlalu kompleks adalah salah satu alasan kebanyakan orang tertarik pada rekayasa perangkat lunak. Jadi ambillah masalah yang rumit ini dan selesaikan dengan cara yang bagus dan tidak terlalu rumit. Apakah itu memerlukan refactoring dan perubahan berisiko? Mungkin tapi begitulah cara menyelesaikannya.

Masih diinginkan. Bahasa lain tidak kesulitan mendukung visibilitas yang berbeda untuk fungsionalitas get- dan set-. Untuk menambahkan cedera penghinaan, TypeScript dibuat oleh Microsoft, seperti C#, tetapi yang terakhir mendukung sepenuhnya:

public string myPropertyWithLimitedAccess { get; private set; }   

Lihat itu. Dapat dibaca dengan indah, dan sama sekali tidak rumit.

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties

Ada sedikit alasan untuk tidak mendukung:

private _myProperty: string;

public get myProperty(): string { return this._myProperty; }
private set myProperty(value: string) { this._myProperty = value; }

Poin bonus dalam keputusan desain yang aneh, karena TypeScript dibuat terutama untuk pengembang .NET agar lebih terbiasa bekerja dengan front-end browser.

+1
TypeScript pasti akan mendapat manfaat dari fungsi ini!

TypeScript sangat bagus bahkan setelah C#, tetapi batasan yang tidak berguna ini cukup sering membuat saya kesal. Silakan buka kembali.

akan meningkatkan kompleksitas bahasa

Apakah ini benar-benar kompleks dibandingkan dengan hal-hal seperti readonly [P in keyof T]: T[P] ?

Menabrak. Semua orang menginginkan fitur ini. Bukankah komunitas TypesScript harus memutuskan?

akan meningkatkan kompleksitas bahasa

Apakah ini benar-benar kompleks dibandingkan dengan hal-hal seperti readonly [P in keyof T]: T[P] ?

Kompleksitas ikut bermain dengan interaksi fitur bahasa lainnya. Sayangnya saya tidak dapat menemukannya, tetapi IIRC RyanCavanaugh memberikan contoh di mana fitur ini memungkinkan Anda untuk mengatur dan kemudian melanggar invarian melalui pewarisan menggunakan ekspresi kelas. Hanya karena mudah untuk menulis deklarasi tertentu, itu tidak berarti akan selalu mudah untuk bernalar tentang bagaimana hal itu mempengaruhi sesuatu.

Pertanyaannya adalah masalah mana yang akan dipecahkan oleh fitur yang diberikan, dan yang akan dibuatnya. Yang pertama mudah dijawab, yang terakhir bisa sangat sulit dijawab. Sayangnya, tim TS terkadang tampaknya merespons dengan "kompleksitas OMG" alih-alih menggambarkan masalahnya. (Agar adil, semakin banyak waktu yang mereka habiskan untuk menjawab kueri x untuk ke-n kalinya, semakin sedikit waktu yang mereka miliki untuk berkembang.)

Saya tidak 100% setuju dengan gagasan "tidakkah komunitas harus memutuskan", karena jika ada konsensus di antara para ahli yang benar-benar mengembangkan bahasa, itu akan memberi tahu Anda sesuatu. Tapi saya pikir dengan sesuatu yang diminta seperti ini, penjelasan yang bijaksana dari tim tentang apa trade-off itu dan mengapa mereka menentangnya tidak terlalu banyak untuk diminta.

Dan secara pribadi, saya pikir trade-off bernilai 1000% dalam kasus ini. Tetapi jika saya tidak mau repot-repot menentukannya dan membuatnya bekerja, saya kira saya tidak punya banyak hak untuk mengeluh.

Apakah ini saat yang tepat untuk meninjau kembali masalah ini?

Pengubah readonly sangat bagus, tetapi ada banyak kasus di mana Anda ingin dapat mengubah nilai di dalam kelas dan masih memiliki semuanya hanya-baca di luar.

Saya sering memilih untuk tidak membuat properti readonly karena saya tidak suka kebisingan yang ditambahkan bidang dukungan pribadi + properti.

Akan sangat bagus jika ada gula sintaksis untuk melakukan ini untuk Anda. Sesuatu seperti:

// Option 1: C# style
public name: string { get; private set; }

// Option 2: Swift style
private(set) name: string

// Option 3: Swift struct-style
public readonly name: string

mutating changeName(name: string) {
  this.name = name
}

// Option 4: New keyword
public frozen name1: string
public readonly name2: string

Saya suka opsi 2, karena itu akan cocok dengan bahasa TypeScript.

Dengan opsi 3, Anda hanya dapat mengubah bidang hanya-baca dalam fungsi yang ditandai sebagai mutating

Dengan opsi 4, frozen hanya dapat diatur dalam konstruktor, readonly dapat diatur di dalam kelas ini, bukan oleh kelas eksternal atau kelas yang mewarisi dari kelas ini.

Untuk referensi, ide @yvbeek tentang pengubah yang lebih fleksibel lebih cocok untuk diskusi di https://github.com/microsoft/TypeScript/issues/37487 .

Masalah ini khusus untuk getter dan setter, dan memiliki jumlah upvotes yang sangat tinggi! Saya pikir akan berguna untuk memberi getter dan setter pengubah akses yang berbeda (dan kami dapat memperbarui set pengubah yang ada di #37487 jika tim TypeScript pernah memutuskannya sebagai hal yang dapat diterima untuk dilanjutkan)

Saya tidak 100% setuju dengan gagasan "tidakkah komunitas harus memutuskan", karena jika ada konsensus di antara para ahli yang benar-benar mengembangkan bahasa, itu akan memberi tahu Anda sesuatu. Tapi saya pikir dengan sesuatu yang diminta seperti ini, penjelasan yang bijaksana dari tim tentang apa trade-off itu dan mengapa mereka menentangnya tidak terlalu banyak untuk diminta.

@snarfblam Tidak menyumbat utas ini dengan komentar yang tidak relevan, tetapi saya pikir Anda telah mengungkapkan prinsip inti tentang cara pemerintah harus beroperasi.

Tidak memiliki fitur ini benar-benar menyakitkan bagi saya dan (antara lain) membuat saya beralih dari TS/NodeJS ke sesuatu yang lebih... ketik safe. Semuanya baik-baik saja dan keren, tetapi ketika Anda sedang mengerjakan proyek yang kompleks dengan banyak struktur data (bersarang berkali-kali) dan Anda tidak dapat memodelkan data dengan benar, Anda merasa bahwa ini bukan bahasa "untuk anak laki-laki".

Dalam kasus khusus saya, saya ingin properti menjadi hanya-baca, tetapi dapat dimodifikasi dari dalam... dan juga diserialisasikan ke JSON. Terlalu banyak rintangan untuk dilewati.

Fitur ini mungkin mengikuti jalur yang sama dengan _rantai opsional_. Orang akan meminta fitur ini selama bertahun-tahun dan akhirnya akan ditambahkan ke bahasa, karena praktis dan bahasa lain menawarkan fitur yang sama.

Kalau tidak, saya berharap beberapa implementasi akan menjadi bagian dari EcmaScript dan kemudian menuju TypeScript.

Saya baru saja beralih ke TypeScript dan saya menyukai bahasanya. Saya benar-benar kecewa karena fitur praktis yang ada dalam bahasa lain ini belum diterapkan di sini. Harap pertimbangkan kembali untuk menambahkannya di rilis mendatang terlepas dari seberapa banyak kerumitan yang menurut Anda mungkin ditambahkan ke bahasa.

Saya mencapai sesuatu yang mirip dengan c# dengan getter seperti itu:

export class I18nService {
  private static ref: I18nService;

  public static get instance(): I18nService {
    if (!I18nService.ref) {
      I18nService.ref = new I18nService();
    }

    return I18nService.ref;
  }
}

Kesalahan ketik seperti berikut ini mudah dipahami dan tidak rumit:

Property 'foo' is writable only in protected scope within class 'Blah' and its subclasses.

atau

Property 'foo' is readable only in protected scope within class 'Blah' and its subclasses.

dll, dan mirip dengan private .

Itu sejujurnya tidak rumit.

BTW, saya juga menemukan masalah ini, dan sementara itu saya menggunakan "peretasan" semacam ini:

// somewhere.ts
declare global {
    type Writable<T> = { -readonly [P in keyof T]: T[P]; }
}

// example.ts
class Example {

    public readonly prop: number;

    public doSomething(n: number): void {
        (this as Writable<this>).prop = n;
    }
}

Secara teknis, ini dapat digunakan di mana saja, tetapi menggunakan solusi ini harus dibatasi pada kode di dalam metode kelas.

BTW, saya juga menemukan masalah ini, dan sementara itu saya menggunakan "peretasan" semacam ini:

Saya sendiri telah memainkan ide ini, tetapi masalahnya adalah Anda tidak memiliki cara untuk membedakan antara properti "hanya-baca publik" dan properti yang benar-benar hanya-baca. Ini membuatnya tidak terlalu cocok sebagai solusi tujuan umum.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat