La primera parte , a juzgar por los comentarios, causó una opinión mixta, especialmente con respecto a la parte de enumeración. En algún lugar también puedo estar en desacuerdo, tanto con el autor del original como con algunos comentarios. Pero como se indica en la descripción inicial de la primera parte, el código limpio no es un dogma a seguir, son solo recomendaciones, cuya observancia eligen todos para satisfacer sus necesidades y puntos de vista.

Objetos y estructuras de datos
Usar inmunidad
El sistema de tipos en TypeScript le permite marcar propiedades individuales de una interfaz / clase como campos de solo lectura (solo lectura) . Esto le permite trabajar funcionalmente (la mutación inesperada es mala). Para escenarios más complejos, hay un tipo Readonly
que toma un tipo T
y marca todas sus propiedades de solo lectura utilizando tipos asignados (ver tipos asignados ).
Malo:
interface Config { host: string; port: string; db: string; }
Bueno
interface Config { readonly host: string; readonly port: string; readonly db: string; }
En el caso de una matriz, puede crear una matriz de solo lectura con ReadonlyArray<T>
. que no permite cambios usando push()
y fill()
, pero puede usar concat()
y slice()
, no cambian los valores.
Malo:
const array: number[] = [ 1, 3, 5 ]; array = [];
Bueno
const array: ReadonlyArray<number> = [ 1, 3, 5 ]; array = [];
Declarar argumentos de solo lectura TypeScript 3.4 es un poco más fácil .
function hoge(args: readonly string[]) { args.push(1);
Preferencias const aserciones para valores literales.
Malo:
const config = { hello: 'world' }; config.hello = 'world';
Bueno
Tipos vs. interfaces
Use tipos cuando necesite unión o intersección. Use la interfaz cuando quiera usar extends
o implements
. Sin embargo, no existe una regla estricta, use lo que funcione para usted. Para una explicación más detallada, vea estas respuestas sobre las diferencias entre type
e interface
en TypeScript.
Malo:
interface EmailConfig {
Bueno
type EmailConfig = {
Clases
Las clases deben ser pequeñas.
El tamaño de una clase se mide por su responsabilidad. Siguiendo el principio de responsabilidad exclusiva, la clase debe ser pequeña.
Malo:
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 { }
Bueno
class Dashboard { disable(): void { } enable(): void { } getVersion(): string { } }
Alta cohesión bajo enlace
La cohesión determina el grado en que los miembros de una clase están relacionados entre sí. Idealmente, todos los campos de una clase deberían ser utilizados por cada método. Decimos que la clase está lo más conectada posible . En la práctica, sin embargo, esto no siempre es posible e incluso indeseable. Sin embargo, debe asegurarse de que la cohesión sea alta.
La conectividad también se refiere a cómo dos clases están relacionadas o dependen unas de otras. Las clases se consideran libremente si los cambios en una de ellas no afectan a la otra.
Malo:
class UserManager {
Bueno
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> {
Prefiere la composición sobre la herencia
Como se dijo en Patrones de diseño de la cuarta banda, debes
Prefiere la composición a la herencia siempre que puedas. Hay muchas buenas razones para usar la herencia y muchas buenas razones para usar la composición. La esencia de este principio es que si su mente instintivamente hereda, intente pensar si la composición puede modelar mejor su problema. En algunos casos, puede.
Entonces puede preguntar: "¿Cuándo debo usar la herencia?" Depende de su problema, pero es una lista decente cuando la herencia tiene más sentido que la composición:
- Su herencia es una relación "es-a" y no una relación "tiene-a" (Humano-> Animal vs. Usuario-> Detalles del usuario).
- Puede reutilizar el código de las clases base (las personas pueden moverse como todos los animales).
- Desea realizar cambios globales en las clases derivadas cambiando la clase base. (Cambio en el gasto calórico en todos los animales al moverlos).
Malo:
class Employee { constructor( private readonly name: string, private readonly email: string) { }
Bueno
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; }
Usar cadenas de llamadas
Este patrón es muy útil y se usa comúnmente en muchas bibliotecas. Esto permite que su código sea expresivo y menos detallado. Por esta razón, use una cadena de métodos y vea qué tan limpio será su código.
Malo:
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 {
Bueno
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 {
Continuará ...