Kode Bersih untuk TypeScript - Bagian 2

Bagian pertama , dilihat dari komentar, menyebabkan pendapat beragam, terutama yang berkaitan dengan bagian enum. Di suatu tempat saya juga bisa tidak setuju, baik dengan penulis asli, dan dengan beberapa komentar. Tetapi seperti yang ditunjukkan dalam uraian awal bagian pertama, kode bersih bukan dogma yang harus diikuti, itu hanya rekomendasi, ketaatan yang dipilih setiap orang untuk menyesuaikan dengan kebutuhan dan pandangan mereka.



Objek dan Struktur Data


Gunakan kekebalan


Sistem tipe dalam TypeScript memungkinkan menandai properti individual dari antarmuka / kelas sebagai bidang yang hanya dapat dibaca (hanya baca) . Ini memungkinkan Anda untuk bekerja secara fungsional (mutasi yang tidak terduga buruk). Untuk skenario yang lebih kompleks, ada tipe Readonly yang mengambil tipe T dan menandai semua properti read-only menggunakan tipe yang dipetakan (lihat tipe yang dipetakan ).


Buruk:


 interface Config { host: string; port: string; db: string; } 

Baik:


 interface Config { readonly host: string; readonly port: string; readonly db: string; } 

Dalam kasus array, Anda bisa membuat array read-only menggunakan ReadonlyArray<T> . yang tidak mengizinkan perubahan menggunakan push() dan fill() , tetapi Anda bisa menggunakan concat() dan slice() mereka tidak mengubah nilainya.


Buruk:


 const array: number[] = [ 1, 3, 5 ]; array = []; // error array.push(100); // array will updated 

Baik:


 const array: ReadonlyArray<number> = [ 1, 3, 5 ]; array = []; // error array.push(100); // error 

Mendeklarasikan Read-Only Argumen TypeScript 3.4 sedikit lebih mudah .


 function hoge(args: readonly string[]) { args.push(1); // error } 

Pernyataan konstanta preferensi untuk nilai literal.


Buruk:


 const config = { hello: 'world' }; config.hello = 'world'; //   const array = [ 1, 3, 5 ]; array[0] = 10; //   //    function readonlyData(value: number) { return { value }; } const result = readonlyData(100); result.value = 200; //   

Baik:


 //     const config = { hello: 'world' } as const; config.hello = 'world'; //  //     const array = [ 1, 3, 5 ] as const; array[0] = 10; //  //        function readonlyData(value: number) { return { value } as const; } const result = readonlyData(100); result.value = 200; //  

Jenis vs antarmuka


Gunakan jenis ketika Anda mungkin membutuhkan penyatuan atau persimpangan. Gunakan antarmuka saat Anda ingin menggunakan extends atau implements . Namun, aturan ketat tidak ada, gunakan yang cocok untuk Anda. Untuk penjelasan lebih rinci, lihat jawaban ini tentang perbedaan antara type dan interface dalam TypeScript.


Buruk:


 interface EmailConfig { // ... } interface DbConfig { // ... } interface Config { // ... } //... type Shape = { // ... } 

Baik:


 type EmailConfig = { // ... } type DbConfig = { // ... } type Config = EmailConfig | DbConfig; // ... interface Shape { // ... } class Circle implements Shape { // ... } class Square implements Shape { // ... } 

Kelas


Kelas harus kecil


Ukuran kelas diukur oleh tanggung jawabnya. Mengikuti prinsip tanggung jawab tunggal, kelas harus kecil.


Buruk:


 class Dashboard { getLanguage(): string { /* ... */ } setLanguage(language: string): void { /* ... */ } showProgress(): void { /* ... */ } hideProgress(): void { /* ... */ } isDirty(): boolean { /* ... */ } disable(): void { /* ... */ } enable(): void { /* ... */ } addSubscription(subscription: Subscription): void { /* ... */ } removeSubscription(subscription: Subscription): void { /* ... */ } addUser(user: User): void { /* ... */ } removeUser(user: User): void { /* ... */ } goToHomePage(): void { /* ... */ } updateProfile(details: UserDetails): void { /* ... */ } getVersion(): string { /* ... */ } // ... } 

Baik:


 class Dashboard { disable(): void { /* ... */ } enable(): void { /* ... */ } getVersion(): string { /* ... */ } } //  ,       // ... 

Ikatan kohesi tinggi, rendah


Kohesi menentukan sejauh mana anggota suatu kelas terkait satu sama lain. Idealnya, semua bidang dalam kelas harus digunakan oleh setiap metode. Kami mengatakan bahwa kelas terhubung mungkin . Namun dalam praktiknya, ini tidak selalu mungkin dan bahkan tidak diinginkan. Namun, Anda harus memastikan bahwa kohesi tinggi.


Konektivitas juga merujuk pada bagaimana dua kelas saling terkait atau bergantung satu sama lain. Kelas dianggap longgar ditambah jika perubahan di salah satu dari mereka tidak mempengaruhi yang lain.


Buruk:


 class UserManager { // :         . //   ,    ,    //      ,     , //       `emailSender`. constructor( private readonly db: Database, private readonly emailSender: EmailSender) { } async getUser(id: number): Promise<User> { return await db.users.findOne({ id }); } async getTransactions(userId: number): Promise<Transaction[]> { return await db.transactions.find({ userId }); } async sendGreeting(): Promise<void> { await emailSender.send('Welcome!'); } async sendNotification(text: string): Promise<void> { await emailSender.send(text); } async sendNewsletter(): Promise<void> { // ... } } 

Baik:


 class UserService { constructor(private readonly db: Database) { } async getUser(id: number): Promise<User> { return await this.db.users.findOne({ id }); } async getTransactions(userId: number): Promise<Transaction[]> { return await this.db.transactions.find({ userId }); } } class UserNotifier { constructor(private readonly emailSender: EmailSender) { } async sendGreeting(): Promise<void> { await this.emailSender.send('Welcome!'); } async sendNotification(text: string): Promise<void> { await this.emailSender.send(text); } async sendNewsletter(): Promise<void> { // ... } } 

Lebih suka komposisi daripada warisan


Seperti yang dikatakan dalam Pola Desain dari Geng Keempat, Anda harus
Lebih suka komposisi untuk warisan di mana pun Anda bisa. Ada banyak alasan bagus untuk menggunakan warisan dan banyak alasan bagus untuk menggunakan komposisi. Inti dari prinsip ini adalah bahwa jika pikiran Anda secara naluriah melanjutkan untuk mewarisi, cobalah untuk berpikir apakah komposisi dapat memodelkan masalah Anda dengan lebih baik. Dalam beberapa kasus, itu bisa.


Kemudian Anda mungkin bertanya: "Kapan saya harus menggunakan warisan?" Itu tergantung pada masalah Anda, tetapi itu adalah daftar yang layak ketika warisan lebih masuk akal daripada komposisi:


  1. Warisan Anda adalah hubungan is-a dan bukan has-a (Human-> Animal vs User-> UserDetails).
  2. Anda dapat menggunakan kembali kode dari kelas dasar (Orang-orang dapat bergerak seperti semua hewan).
  3. Anda ingin membuat perubahan global ke kelas turunan dengan mengubah kelas dasar. (Ubah pengeluaran kalori pada semua hewan saat memindahkan mereka).

Buruk:


 class Employee { constructor( private readonly name: string, private readonly email: string) { } // ... } // ,   Employees ""  . EmployeeTaxData    Employee class EmployeeTaxData extends Employee { constructor( name: string, email: string, private readonly ssn: string, private readonly salary: number) { super(name, email); } // ... } 

Baik:


 class Employee { private taxData: EmployeeTaxData; constructor( private readonly name: string, private readonly email: string) { } setTaxData(ssn: string, salary: number): Employee { this.taxData = new EmployeeTaxData(ssn, salary); return this; } // ... } class EmployeeTaxData { constructor( public readonly ssn: string, public readonly salary: number) { } // ... } 

Gunakan rantai panggilan


Pola ini sangat berguna dan umumnya digunakan di banyak perpustakaan. Ini memungkinkan kode Anda menjadi ekspresif dan kurang bertele-tele. Karena alasan ini, gunakan serangkaian metode dan lihat seberapa bersih kode Anda.


Buruk:


 class QueryBuilder { private collection: string; private pageNumber: number = 1; private itemsPerPage: number = 100; private orderByFields: string[] = []; from(collection: string): void { this.collection = collection; } page(number: number, itemsPerPage: number = 100): void { this.pageNumber = number; this.itemsPerPage = itemsPerPage; } orderBy(...fields: string[]): void { this.orderByFields = fields; } build(): Query { // ... } } // ... const queryBuilder = new QueryBuilder(); queryBuilder.from('users'); queryBuilder.page(1, 100); queryBuilder.orderBy('firstName', 'lastName'); const query = queryBuilder.build(); 

Baik:


 class QueryBuilder { private collection: string; private pageNumber: number = 1; private itemsPerPage: number = 100; private orderByFields: string[] = []; from(collection: string): this { this.collection = collection; return this; } page(number: number, itemsPerPage: number = 100): this { this.pageNumber = number; this.itemsPerPage = itemsPerPage; return this; } orderBy(...fields: string[]): this { this.orderByFields = fields; return this; } build(): Query { // ... } } // ... const query = new QueryBuilder() .from('users') .page(1, 100) .orderBy('firstName', 'lastName') .build(); 

Dilanjutkan ...

Source: https://habr.com/ru/post/id485068/


All Articles