Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
jbrantly opened this issue Feb 12, 2015 · 11 comments
Labels
Duplicate An existing issue was already created Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript

Comments

@jbrantly
Copy link

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?

@jbrantly
Copy link
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?

@mhegazy
Copy link
Contributor

mhegazy commented Feb 16, 2015

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.

@mhegazy mhegazy added Question An issue which isn't directly actionable in code and removed Question An issue which isn't directly actionable in code labels Feb 16, 2015
@jbrantly
Copy link
Author

@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.

@mhegazy mhegazy added Suggestion An idea for TypeScript Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. and removed Question An issue which isn't directly actionable in code labels Feb 17, 2015
@jbrantly
Copy link
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";
}

@mhegazy
Copy link
Contributor

mhegazy commented Feb 23, 2015

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;
}

@jbrantly
Copy link
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.

@mhegazy
Copy link
Contributor

mhegazy commented Feb 23, 2015

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?

@jbrantly
Copy link
Author

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

@jbrantly
Copy link
Author

For clarity: "third party library written in UMD"

@mhegazy
Copy link
Contributor

mhegazy commented Feb 23, 2015

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

@mhegazy
Copy link
Contributor

mhegazy commented Feb 22, 2016

closing in favor of #7125

@mhegazy mhegazy closed this as completed Feb 22, 2016
@mhegazy mhegazy added the Duplicate An existing issue was already created label Feb 22, 2016
@microsoft microsoft locked and limited conversation to collaborators Jun 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

2 participants