Skip to content

Create "Global / External-agnostic" declaration files without exposing internal definitions #2018

Description

Say I'm writing a declaration file for an external library that both exposes a global and supports CommonJS. According to the handbook I would write that like this:

module zoo {
  function open(): void;
}

declare module "zoo" {
    export = zoo;
}

And then the usage would be this:

// Either
import x = require('zoo');
x.open();
// or
zoo.open();

The problem is that while the above would compile when using external modules, at run-time it would fail since the "zoo" identifier doesn't actually exist. Is there any way to write declaration files such that you can split them into two separate files (one for internal, one for external) so that you only reference the one you intend on using but not actually duplicate the definitions in those files? For example

// zoo.d.ts
declare module "zoo" {
    export = zoo;
}

// zoo-internal.d.ts

/// <reference path="zoo.d.ts" />
module zoo {
  // this doesn't work but illustrates what I'm trying to accomplish
  import zoo = require('zoo')
  export = zoo;
}

Or any thoughts on another way to accomplish the same goals in a single file?

Activity

  1. jbrantly commented on Feb 12, 2015

    @jbrantly
    Author

    It was brought to my attention that the TypeScript team actually solves this internally by scripting. https://github.com/Microsoft/TypeScript/blob/42c05453bd5f2b1c4e75cd2fff1d2b55434119c0/Jakefile#L352-L356

    Any plans on supporting it at the language level?

  2. mhegazy commented on Feb 16, 2015

    @mhegazy
    Contributor

    The compiler can not force the existence of js code. Simply because it does not know about it. If you are exposing an internal module, then it is the responsibility of your users to load the library js code, either through a script tag, bundling it at build time or using a resource loader. This is the same in the case of most libraries definitions, say jquery.d.ts, you need to include the .js file independently from the definition.

    If your library is available in two modes, e.g. a universal module implementation, then I would recommend releasing two declaration files, one for each mode just to avoid confusion. This is what we did for typescript package definition. What the compiler does not support is generations both files in the same compilation, namely multi file external modules, which is a highly requested feature and I would expect us to support it in the future. For the time being we worked around by copying the file and addng the export statement. There are a few tools out there that can help you out.

    If however your module have global side effects, then that is a different issue. The language does not support modeling of these global side effects and I would argue that it should not be added in the future either.

  3. added
    QuestionAn issue which isn't directly actionable in code
    and removed
    QuestionAn issue which isn't directly actionable in code
    on Feb 16, 2015
  4. jbrantly commented on Feb 17, 2015

    @jbrantly
    Author

    Mohamed Hegazy (@mhegazy) Thanks for your response.

    The compiler can not force the existence of js code.

    To be clear, I wasn't asking for this.

    If your library is available in two modes, e.g. a universal module implementation, then I would recommend releasing two declaration files, one for each mode just to avoid confusion.

    This is exactly what I was asking about. I don't mind releasing two declaration files. The problem, currently, is that both declaration files have 99% duplication. I'm asking for a language feature which will remove this duplication. As one possible example of such a language feature, you could allow an internal module declaration to import an external module declaration and then append the external module's exports to that of the internal module's. (see my example in the original post)

    What the compiler does not support is generations both files in the same compilation

    I'm talking about writing declarations for pre-existing libraries, not for libraries written in TypeScript.

  5. added
    SuggestionAn idea for TypeScript
    Needs ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.
    and removed
    QuestionAn issue which isn't directly actionable in code
    on Feb 17, 2015
  6. jbrantly commented on Feb 23, 2015

    @jbrantly
    Author

    It seems like #1983 might provide a solution to this if it allowed usage within an internal module declaration. For example:

    // zoo.d.ts
    declare module "zoo" {
      export function open(): void;
    }
    
    // zoo-internal.d.ts
    
    /// <reference path="zoo.d.ts" />
    module zoo {
      export * from "zoo";
    }
    
  7. mhegazy commented on Feb 23, 2015

    @mhegazy
    Contributor

    I am afaraid that is not going to work either. export * from "mod" are only allowed in external modules.

    You can do the oposite though:

    // zoo-internal.d.ts
    declare module zoo {
      export function open(): void;
    }
    
    // zoo.d.ts
    /// <reference path="zoo-internal.d.ts" />
    declare module "zoo" {
      export = zoo;
    }
  8. jbrantly commented on Feb 23, 2015

    @jbrantly
    Author

    Unfortunately that gets back to the original issue, which is that by referencing zoo.d.ts you get both the external module and the internal module.

    Is there any reason that the export * from "identifer" can't be allowed within an internal module declaration? Presumably it just re-exports the existing members.

  9. mhegazy commented on Feb 23, 2015

    @mhegazy
    Contributor

    The problem really is you can not mix external into internal. think of internal modules as namespaces, so they are just simple IIFE's that have a name.. external modules require loading and dependency resolution and detection. so when i use the internal module zoo, would that be rewritten as a require call?

  10. jbrantly commented on Feb 23, 2015

    @jbrantly
    Author

    Keep in mind I'm only talking about declaration files here for an external module written in UMD.

  11. jbrantly commented on Feb 23, 2015

    @jbrantly
    Author

    For clarity: "third party library written in UMD"

  12. mhegazy commented on Feb 23, 2015

    @mhegazy
    Contributor

    We need a proposal for this one. I understand that this is a pain point, and we need a solution.

  13. mhegazy commented on Feb 22, 2016

    @mhegazy
    Contributor

    closing in favor of #7125

  14. locked and limited conversation to collaborators on Jun 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already createdNeeds ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.SuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions