GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Guidance on writing declaration file for multi-targeted libraries · Issue #4337 · microsoft/TypeScript

Guidance on writing declaration file for multi-targeted libraries #4337

New issue
Copy link
New issue
Copy link
Closed
Closed
Guidance on writing declaration file for multi-targeted libraries#4337
Copy link
Assignees
RyanCavanaugh
Labels
@typesRelates to working with .d.ts files (declaration/definition files) from DefinitelyTypedRelates to working with .d.ts files (declaration/definition files) from DefinitelyTypedCommittedThe team has roadmapped this issueThe team has roadmapped this issueSuggestionAn idea for TypeScriptAn idea for TypeScript

Description

@jbrantly
James Brantly (jbrantly)
opened on Aug 17, 2015
Issue body actions

It is now possible for a library to hit every type of target that TypeScript supports (module, namespace, and ES6). Currently, writing a declaration file for a library like this can be very challenging. The default today is something like this:

declare namespace MyLib {
   export ...
}

declare module 'mylib' {
  export = MyLib;
}

This has a couple issues:

  1. If you're using this in the module sense, using this declaration file will result in TypeScript thinking there is a globally available variable MyLib which is not actually true. This can lead to runtime errors. (see Create "Global / External-agnostic" declaration files without exposing internal definitions #2018)
  2. If you're using ES6 import syntax TypeScript will consider this module to be in the CommonJS style and will not allow default imports even though the library actually supports them.

In the past, regarding item 1, it's been suggested that we split the declarations into two files (one for modules and one for namespaces). This makes sense. I think it also makes sense to extend that concept for ES6 modules. So if you have a library that targets all three, then you will have three mutually exclusive declaration files. Where things then become problematic is with duplicating the declarations in each file (which ideally should not happen). It is impossible to import an ambient module into an ambient namespace. It is possible to use an ambient namespace in an ambient module, but a naive approach to that (as shown in the common case above) violates item 1.

Therefore, I propose this guidance to writing these declaration files.

// mylib-common.d.ts

declare namespace __MyLib {
  export ...
}

// mylib-namespace.d.ts

/// <reference path="mylib-common.d.ts" />
import MyLib = __MyLib;

// mylib-module.d.ts

/// <reference path="mylib-common.d.ts" />
declare module 'mylib' {
  export = __MyLib;
}

// mylib-es6.d.ts

/// <reference path="mylib-common.d.ts" />
declare module 'mylib' {
  export * from __MyLib; // this doesn't currently work, see #4336
  export default __MyLib; // if there is a default export
}

Unfortunately this is currently hypothetical since you cannot re-export namespace declarations from an ES6 declaration.

I'm proposing this as a baseline for discussion to solve this issue for good. It's possible I'm going down the wrong track or that there is already a better way to handle these cases. It would also be great if we could get some buy-in from the TypeScript language to solve this, if needed.

Some possible ways TypeScript could be improved in this area:

  1. Fix Re-exporting namespace declarations in ES6 ambient declaration #4336
  2. Make it so that __MyLib only exists as a namespace and not as a value, either through convention (prefixed with __) or through additional syntax.

cc John Reilly (@johnnyreilly) Masahiro Wakame (@vvakame)

Reacted by Michael Ledin

Activity

  1. johnnyreilly commented on Aug 17, 2015

    @johnnyreilly
    John Reilly (johnnyreilly)
    on Aug 17, 2015
    More actions

    I'd love to hear what other people have to say about this - I'm in agreement that things are somewhat broken at present.

    As a little digression, I've just taken over an app that is built using Browserify + Babel and written in ES6. I'd hoped I'd be able to drop TypeScript into the mix by just having it export ES6 which can then be processed by Babel but found that the definition file story was very wanting indeed. For now I've had to bail on the issue.

    Thanks for writing this up James Brantly (@jbrantly) - hopefully something good will result!

  2. Ryan Cavanaugh (RyanCavanaugh)
    added
    SuggestionAn idea for TypeScriptAn idea for TypeScript
    In DiscussionNot yet reached consensusNot yet reached consensus
    on Aug 18, 2015
  3. mhegazy commented on Sep 5, 2015

    @mhegazy
    Mohamed Hegazy (mhegazy)
    on Sep 5, 2015
    Contributor
    More actions

    As a little digression, I've just taken over an app that is built using Browserify + Babel and written in ES6. I'd hoped I'd be able to drop TypeScript into the mix by just having it export ES6 which can then be processed by Babel but found that the definition file story was very wanting indeed. For now I've had to bail on the issue.

    John Reilly (@johnnyreilly), Is the export * from namespace the only issue you ran into, or are there other issues?

  4. johnnyreilly commented on Sep 5, 2015

    @johnnyreilly
    John Reilly (johnnyreilly)
    on Sep 5, 2015
    More actions

    Hi Mohamed Hegazy (@mhegazy) ,

    I can't remember the details offhand. I'll reattempt and report back. - I'll try and give you access to a repo that produces whatever issues I face as well.

  5. jkillian commented on Oct 30, 2015

    @jkillian
    Jason Killian (jkillian)
    on Oct 30, 2015
    More actions

    👍 While I haven't looked into things enough to know if the initial proposal is the best solution or not, I've had difficulties working with CommonJS libraries when targeting ES6. A standardized, obvious way of doing things would be a plus.

  6. glen-84 commented on Nov 24, 2015

    @glen-84
    Glen (glen-84)
    on Nov 24, 2015
    More actions

    I'm trying to use the type definitions for Gulp.

    Are the only options right now:

    1. Target ES5/CommonJS and use the old syntax: import gulp = require("gulp");
    2. Target ES6, use the new syntax, but the definition must be changed to export default x instead of export = x.

    ?

    For the 2nd option, if I send PRs to have various definitions updated, will that break applications using older (or even current) versions of TypeScript?

    This is so confusing. 😞

  7. Mohamed Hegazy (mhegazy)
    added
    @typesRelates to working with .d.ts files (declaration/definition files) from DefinitelyTypedRelates to working with .d.ts files (declaration/definition files) from DefinitelyTyped
    on Feb 22, 2016
  8. Mohamed Hegazy (mhegazy)
    assigned
    Ryan Cavanaugh (RyanCavanaugh)
    on Feb 22, 2016
  9. Ryan Cavanaugh (RyanCavanaugh)
    added
    CommittedThe team has roadmapped this issueThe team has roadmapped this issue
    and removed
    In DiscussionNot yet reached consensusNot yet reached consensus
    on Apr 11, 2016
  10. patsissons commented on May 6, 2016

    @patsissons
    Pat Sissons (patsissons)
    on May 6, 2016
    More actions

    Just a note, I have run into this before when authoring various react related typescript definitions. the approach I have been using, which is similar to James Brantly (@jbrantly)'s concept, is to use the (somewhat new) export import syntax. This has the obvious caveat that you must export everything explicitly, but it does function within typescript.

    /// <reference path="../../../typings/main/ambient/react/index.d.ts" />
    
    declare namespace __MyLib {
      export interface ThingProps extends __React.HTMLAttributes {
        text: string;
      }
      export class Thing extends __React.Component<ThingProps, any> { }
    }
    
    import MyLibExports = __MyLib;
    
    declare module 'mylib' {
      export import ThingProps = MyLibExports.ThingProps;
      export import Thing = MyLibExports.Thing;
      export default MyLibExports.Thing;
    }
  11. mhegazy commented on Jul 21, 2016

    @mhegazy
    Mohamed Hegazy (mhegazy)
    on Jul 21, 2016
    Contributor
    More actions

    Documentation can be found at https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/declaration%20files/Introduction.md

    Reacted by Michael Ledin
  12. Mohamed Hegazy (mhegazy)
    closed this as completedon Jul 21, 2016
  13. microsoft
    locked and limited conversation to collaborators on Jun 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

  • @RyanCavanaugh
    Ryan Cavanaugh (RyanCavanaugh)

Labels

@typesRelates to working with .d.ts files (declaration/definition files) from DefinitelyTypedRelates to working with .d.ts files (declaration/definition files) from DefinitelyTypedCommittedThe team has roadmapped this issueThe team has roadmapped this issueSuggestionAn idea for TypeScriptAn idea for TypeScript

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.