Skip to content

Suggestion: package declaration file for commonjs packages #3089

Closed
@rbuckton

Description

@rbuckton

Proposal

To better support the development and consumption of node.js modules in TypeScript, I propose that we add the ability to emit a single declaration file for a node.js package. To that end, I suggest we add the following features:

  • Add a packageName compiler option, used to specify the name of the node.js package.
  • Add a packageMain compiler option, used to specify the path to the main typescript module for the package.
  • Add a packageDeclaration compiler option, used to specify the output path of the declaration file for the package.
  • When the above three options are supplied, along with declaration and either module or a target of ES6, we should emit a single declaration file for the program inputs.

The output for a packageDeclaration would have the following form:

  • Exports for the main module will be defined inside of an ambient external module that has the name provided via packageName.
  • Exports for relative modules will be defined inside of an ambient external module that has a name derived from the package name, and the path of the module relative to the nearest package.json file, common directory path, or the current directory.

Example

Given the following sources:

a.ts

import { C } from "./lib/b"; 
export function func(): C {
    return new C();
}

lib\b.ts

export class C {
}

index.ts

export * from "./a";

And the following command line:

tsc index.ts a.ts lib/b.ts --module commonjs --declaration --packageName sample --packageMain index.ts --packageDeclaration sample.d.ts

You would get the following package declaration output file:

sample.d.ts

declare module "sample" {
    export * from "sample/a";
}
declare module "sample/a" {
    import { C } from "sample/lib/b";
    function func(): C;
}
declare module "sample/lib/b" {
    class C {
    }
}

Out of scope

It would be nice to also be able to emit only the exports visible from the main module, and reduce the overall output side of the declaration file, but not all node.js packages are designed to work that way. Instead, in the future we could investigate an option to choose whether to emit a single ambient module declaration. The proposed approach can be used whether you intend to have a single output module or the ability to reach nested submodules, while the more restrictive approach would alienate some package authors.

It is also out of scope to infer package information from the package.json file, although that may be considered in the future. That might look something like having a package compiler option that can read the package.json file to infer the packageName from the "name" field of the package, and the packageDeclaration from the "typings" (proposed) field of the package. However, its more complicated to derive packageMain as the "main" field of the package will be pointing to the output file and not the original typescript file. We might have to propose a "devMain", or some
other similarly named field, to satisfy this requirement.

As proposed, using packageDeclaration will circumvent regular declaration file generation. We could opt to support both, by writing individual declaration files for each non-declaration input as well as the package-level declaration, though I am not certain whether that would be necessary.

A sample implementation for this proposal can be found in the packageDeclaration2 branch.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DeclinedThe issue was declined as something which matches the TypeScript visionSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions