Difference between classes and namespaces in types

2019-07-08 10:21发布

问题:

What is exactly the difference between Classes and Namespaces in Typescript? I know that if you create a class with static methods you can access them without instantiate the class and that is exactly one of the points of namespaces I guess.

I also know that you can create more than one Namespace with the same name and their methods will belong to the same function when compiled to JS.

But I cant figure out when to use one or another...for me, at the end, classes and namespaces are almost the same, so I guess I am missing something...

回答1:

You're right. Namespaces and static classes are similar. They have some common features. They are both syntactical sugar of ES5 patterns that share similarities - cf. transpiled JavaScript given by the TypeScript playground:

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

Yet, they have also their own features:

  • Namespaces are only in TypeScript and not in ECAMScript. They can be seen as IIFE syntactical sugar. They can be nested (e.g. A.B.C) to ressemble C# namespaces. Since ECMAScript 6 (ES6/ES2015), in most cases ES6 modules are more interesting than namespaces because it's simplier to handle nesting at the file level and keep the code structure flat.

  • Classes including static members are also available in ES6. They are also syntactical sugar of the "constructor function pattern". A static class offers the same features than a namespace but with a syntax less usual - see previous example.

So fundamentally each pattern has its own philosophy related to these use cases:

  • For static (i.e. +/- global) members: ES6 modules in most cases; TypeScript namespaces sometimes, even inside a module - see TS Doc; or just a constant object literal,
  • To create object: classes (that can have static members too by the way, like factory methods), factory functions, just plain object literals, ...

These suggestions can help produce code more "idiomatic" i.e. easier to read and to maintain.

But you / your team own your code and the decision is yours. You may try different patterns to compare them based on your experience. Finally, if it's your choice, using pure static classes over namespaces is not bad, like using namespaces instead of ES6 modules.



回答2:

But I cant figure out when to use one or another...for me, at the end, classes and namespaces are almost the same, so I guess I am missing something...

Use classes when you want to create instances of it e.g.

class Foo {
 x = 0
}
const foo = new Foo(); // instantiate

Use namespaces only when you need to group similar classes / functions / variables etc e.g

namespace Foo {
  export class Bar {}
  export class Bas {}
}

Overlap

There is overlap in end usage syntax e.g. statics on classes can be abused to behave like namespaces. If you follow this guide you can ignore that overlap.