رمز نظيف لـ TypeScript - الجزء 2

الجزء الأول ، استنادا إلى التعليقات ، تسبب في رأي متباين ، وخاصة فيما يتعلق بجزء التعداد. في مكان ما يمكنني أيضًا أن أختلف معه ، سواء مع مؤلف النص الأصلي أو مع بعض التعليقات. ولكن كما هو موضح في الوصف الأولي للجزء الأول ، فإن الشفرة النظيفة ليست عقيدة يجب إتباعها ، إنها مجرد توصيات يختار الجميع مراعاتها لتناسب احتياجاتهم ووجهات نظرهم.



الكائنات وهياكل البيانات


استخدام الحصانة


يتيح لك نظام الكتابة في TypeScript وضع علامة على الخصائص الفردية للواجهة / الفئة كحقول للقراءة فقط (للقراءة فقط) . يتيح لك ذلك العمل وظيفيًا (حدوث طفرة غير متوقعة سيء). بالنسبة للسيناريوهات الأكثر تعقيدًا ، يوجد نوع Readonly مدمج يأخذ نوع T ويميز جميع خصائصه للقراءة فقط باستخدام الأنواع المعينة (انظر الأنواع المعينة ).


الفقراء:


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

حسن:


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

في حالة صفيف ، يمكنك إنشاء صفيف ReadonlyArray<T> باستخدام ReadonlyArray<T> . التي لا تسمح بالتغييرات باستخدام push() و fill() ، لكن يمكنك استخدام concat() و slice() لا يغيران القيم.


الفقراء:


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

حسن:


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

إعلان وسيطات للقراءة فقط TypeScript 3.4 أسهل قليلاً .


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

تأكيدات التفضيلات const للقيم الحرفية.


الفقراء:


 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; //   

حسن:


 //     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; //  

أنواع مقابل واجهات


استخدم أنواعًا عندما تحتاج إلى اتحاد أو تقاطع. استخدم الواجهة عندما تريد استخدام extends أو implements . ومع ذلك ، لا توجد قاعدة صارمة ، استخدم ما يناسبك. للحصول على شرح أكثر تفصيلاً ، راجع هذه الإجابات حول الاختلافات بين type interface في TypeScript.


الفقراء:


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

حسن:


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

فصول


يجب أن تكون الفصول صغيرة


يقاس حجم الفصل بمسؤوليته. باتباع مبدأ المسؤولية الفردية ، يجب أن يكون الفصل صغيراً.


الفقراء:


 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 { /* ... */ } // ... } 

حسن:


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

ارتفاع التماسك منخفضة السندات


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


يشير الاتصال أيضًا إلى كيفية ارتباط فئتين أو اعتمادهما على بعضهما البعض. تعتبر الفصول الدراسية مترابطًا إذا كانت التغييرات في أحدها لا تؤثر على الآخر.


الفقراء:


 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> { // ... } } 

حسن:


 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> { // ... } } 

تفضل التكوين على الميراث


كما قيل في أنماط التصميم من عصابة الرابع ، يجب عليك
تفضل تكوين الميراث أينما استطعت. هناك العديد من الأسباب الجيدة لاستخدام الميراث والعديد من الأسباب الجيدة لاستخدام التكوين. يكمن جوهر هذا المبدأ في أنه إذا استمر عقلك غريزيًا في الميراث ، فحاول أن تفكر فيما إذا كانت التركيبة يمكنها أن تصوغ مشكلتك بشكل أفضل. في بعض الحالات ، يمكن.


ثم قد تسأل: "متى يجب أن استخدم الميراث؟" هذا يعتمد على مشكلتك ، لكنها قائمة جيدة عندما يكون الميراث أكثر منطقية من التكوين:


  1. الميراث الخاص بك هو علاقة "is-a" وليست علاقة "has-a" (الإنسان - الحيوان مقابل المستخدم - تفاصيل المستخدم).
  2. يمكنك إعادة استخدام الشفرة من الفئات الأساسية (يمكن للأشخاص التنقل مثل جميع الحيوانات).
  3. تريد إجراء تغييرات عمومية على الفئات المشتقة عن طريق تغيير الفئة الأساسية. (التغير في الإنفاق من السعرات الحرارية في جميع الحيوانات عند نقلها).

الفقراء:


 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); } // ... } 

حسن:


 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) { } // ... } 

استخدام سلاسل الاتصال


هذا النمط مفيد للغاية ويشيع استخدامه في العديد من المكتبات. هذا يسمح رمز الخاص بك لتكون معبرة وأقل مطول. لهذا السبب ، استخدم سلسلة من الطرق وشاهد مدى نظافة الكود.


الفقراء:


 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(); 

حسن:


 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(); 

أن تستمر ...

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


All Articles