Skip to content

Consider deprecating namespaces declared with the module keyword #51825

Open
@DanielRosenwasser

Description

@DanielRosenwasser

Background

Today, TypeScript has two uses of the module keyword.

The first is called an "ambient module declaration".

declare module "some-library" {
  // ...
}

declare module "*.css";

While we often prefer people author declaration files and submit them to DefinitelyTyped, the declare module syntax here is fine.

The second use is for namespace declarations.

module foo {}
declare module bar.baz {}

This is odd - these are called "namespace" declarations? Well, namespace declarations support using either the namespace keyword, or the module keyword. You could replace module with namespace in that last code snippet and it would work the same.

But why? Why support two ways to do the same thing? Because originally, TypeScript was designed with speculation that JavaScript would have two organizational schemes: "external modules" and "internal modules". External modules were files with isolated top-level scopes that could import/export values. Internal modules were named blocks of code that could export values.

Eventually, JavaScript just got "external modules" and called them "modules". TypeScript was left with two concepts and eventually it was too confusing. So in TypeScript 1.5, we introduced the namespace keyword to make the distinction clearer. Over time, the community preferred using the namespace keyword and linters discouraged the use of module in their place.

Recently, TC39 has been discussing two additions to JavaScript - module expressions and module declarations. These proposals have some overlap with namespaces, but ultimately act different and enable different functionality. Regardless of whether we support the proposals or they go in, during discussion, most people were surprised that the use of module for namespaces wasn't at least deprecated.

As we discuss TypeScript 5.0, we're considering some cleanup in the flag and language space.

Deprecation Proposal

In #51813, we discussed the matter and felt comfortable with deprecating the use of the module keyword in namespace declarations. Deprecation plans are guided by plans discussed at #51000.

What this would amount to is a graceful parse on any namespace declaration declared with module. In editor scenarios, our language service would provide a quick fix to replace that keyword with namespace. When "ignoreDeprecations"": "5.0" is turned on, we would still provide an editor suggestion which would enable the same quick fix.

Caveats

This plan seems sound in implementation files; however, if a module-declared namespace appears in a declaration file from a 3rd party package, you're out of luck. At best, we could only error on implementation files.

So it's unclear if we'll be stuck with module keyword-declared namespaces in .d.ts files forever, or if this is possibly the first step in phasing that out too. Even if we wanted to support the module declarations proposal, it seems unclear whether we could when declaration files still contain module keyword-declared namespaces.

Reconsideration

Here's a few points to consider:

  • The work to deprecate is higher than the maintenance of the module keyword over the last 8 years. In fact, writing this deprecation plan was more work than that.
  • Forcing namespace users off of module in implementation files seems fine, but it feels kind of pointless if we can't break them in declaration files.
  • To some extent, erroring on a keyword that no new code uses anyway feels like a break for the sake of purity. It heavily favors conceptual cleanliness for implementers without much benefit for people using TypeScript.

Metadata

Metadata

Assignees

No one assigned

    Labels

    In DiscussionNot yet reached consensusSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions