javascript - Diferencia entre clases y espacios de nombres en TypeScript
¿Cuál es exactamente la diferencia entre clases y espacios de nombres en TypeScript? Sé que si creas una clase con métodos estáticos puedes acceder a ellos sin instanciar la clase y eso es exactamente uno de los puntos de los espacios de nombres, supongo.
También sé que puedes crear más de un espacio de nombres con el mismo nombre y sus métodos pertenecerán a la misma función cuando se compile a JS.
Pero no puedo averiguar cuándo usar uno u otro... para mí, al final, las clases y los espacios de nombres son casi lo mismo, así que supongo que me estoy perdiendo de algo...
Respuesta #1
Tienes razón. Los espacios de nombres y las clases estáticas son similares. Tienen algunas características en común. Ambos son azúcar sintáctica de los patrones de ES5 que comparten similitudes - cf. JavaScript transpiligado proporcionado por el playground de TypeScript:
// TypeScript
class C {
static readonly Name = 'C';
static print() {
console.log(`Name=${C.Name}`);
}
}
namespace N {
export const Name = 'N';
export function print() {
console.log(`Name=${Name}`);
}
}
// Usage
C.print();
N.print();
const c = new C();
const n = new N(); // TS Error: Cannot use 'new' with an expression whose type lacks a call or a construct signature
// Transpiled JavaScript
var C = /** @class */ (function () {
function C() {
}
C.print = function () {
console.log("Name=" + C.Name);
};
C.Name = 'C';
return C;
}());
var N;
(function (N) {
N.Name = 'N';
function print() {
console.log("Name=" + N.Name);
}
N.print = print;
})(N || (N = {}));
Sin embargo, también tienen sus propias características:
Namespaces solo están en TypeScript y no en ECMAScript. Pueden considerarse como azúcar sintáctica de IIFE. Pueden ser anidados (por ejemplo,
A.B.C) para asemejarse a los namespaces de C#. Desde ECMAScript 6 (ES6/ES2015), en la mayoría de los casos, los módulos ES6 son más interesantes que los namespaces porque es más sencillo manejar la anidación a nivel de archivo y mantener la estructura del código plana.Clases que incluyen miembros estáticos también están disponibles en ES6. También son azúcar sintáctico del "patrón de función constructora". Una clase estática ofrece las mismas características que un espacio de nombres pero con una sintaxis menos habitual - vea el ejemplo anterior.
Entonces, fundamentalmente, cada patrón tiene su propia filosofía relacionada con estos casos de uso:
- Para miembros estáticos (es decir, globales +/-): módulos ES6 en la mayoría de los casos; namespaces de TypeScript a veces, incluso dentro de un módulo - ver Doc de TS; o simplemente un objeto literal constante,
- Para crear objetos: clases (que también pueden tener miembros estáticos, por cierto, como métodos de fábrica), funciones de fábrica, simplemente literales de objetos, ...
Estas sugerencias pueden ayudar a producir código más "idiomático", es decir, más fácil de leer y de mantener.
Pero tú/tu equipo son los dueños de tu código y la decisión es tuya. Puedes probar diferentes patrones para compararlos según tu experiencia. Finalmente, si es tu elección, usar clases estáticas puras en lugar de namespaces no está mal, al igual que usar namespaces en lugar de módulos ES6.
Respuesta #2
Pero no puedo entender cuándo usar uno u otro... para mí, al final, las clases y los espacios de nombres son casi lo mismo, así que supongo que me estoy perdiendo de algo...
Usa clases cuando quieras crear instancias de ellas, por ejemplo.
class Foo {
x = 0
}
const foo = new Foo(); // instantiate
Usa espacios de nombres solo cuando necesites agrupar clases/funciones/variables similares, etc.
namespace Foo {
export class Bar {}
export class Bas {}
}
Superposición
Hay superposición en la sintaxis de uso final, por ejemplo, los estáticos en las clases pueden ser abusados para comportarse como espacios de nombres. Si sigues esta guía, puedes ignorar esa superposición.
