Why the ES2015 module syntax is preferred over custom TypeScript namespaces?
Asked Answered
S

1

7

From typescript-eslint docs:

Custom TypeScript modules (module foo {}) and namespaces (namespace foo {}) are considered outdated ways to organize TypeScript code. ES2015 module syntax is now preferred (import/export).

From Typescripts docs

Modules can contain both code and declarations.

Modules also have a dependency on a module loader (such as CommonJs/Require.js) or a runtime which supports ES Modules. Modules provide for better code reuse, stronger isolation and better tooling support for bundling.

It is also worth noting that, for Node.js applications, modules are the default and we recommended modules over namespaces in modern code.

My goal with this question is to find out why the module syntax is preferred over namespaces.

Here is what I've been doing so far:

PROJECT_TYPES.d.ts

I have multiple d.ts files where I declare namespaces containing the types that I use across my project's source files.

declare namespace MY_NAMESPACE {
  type FOO = "FOO"
}

Doing it like this, I can do the following inside any source file of my project:

someFile.ts

const foo: MY_NAMESPACE.FOO =  "FOO";

And it works without the need of any import/export.

Notes:

  • I'm using d.ts files because those files do not contain any import / export code.
  • I'm using declare namespace instead of just namespace because without the declare keyword I get a @typescript-eslint/no-unused-vars warning.

Considering that MY_NAMESPACE is a unique name, should this be considered a bad practice? In this scenario, is there a reason I should use modules over namespaces ? Should I not use d.ts files?

I mean, the Typescript docs mentions that:

Modules provide for better code reuse, stronger isolation and better tooling support for bundling.

But I don't think I'm losing any of those benefits by following the pattern I described above, since all my "real" actual compiled result code are separated in modules. But why my types should be solely in modules?

Streamlet answered 24/9, 2020 at 9:27 Comment(0)
O
6

The purpose of namespace is to provide logical grouping of constructs, but the introduction of ES2015 modules allows us to achieve this using the filesystem without polluting the global scope.

It also gives us more flexibility when using the types, and we can infer the namespace using directories.

Example

Pre ES2015

// src/geometry/types.d.ts
declare namespace Geometry{
    export type Shape = 'circle' | 'square'
}

// src/geometry/main.ts
let myShape: Geometry.Shape = 'square'

Post ES2015

Note in main.js we aren't using the Geometry prefix, which makes sense because we're already in the geometry directory

// src/geometry/types.ts
export type Shape = 'circle' | 'square'

// src/geometry/main.ts
import { Shape } from './types'
let myShape: Shape = 'square'

//src/geometry/index.ts
export * from './types'
export * from './main'

//src/index.ts
export * as Geometry from './geometry'

Reference

Och answered 20/10, 2021 at 1:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.