Typescript: Use d.ts specified types within a JavaScript Module Itself

Created on 27 Feb 2017  路  12Comments  路  Source: microsoft/TypeScript



From https://github.com/Microsoft/vscode/issues/21454

TypeScript Version: 2.2.1

Code
For a javascript project
a.js:

export function abc( x, y ) { }

a.d.ts:

export declare function abc(x: number, y: number): boolean;

b.js

import { abc } from './a'

Expected behavior:
Within both a.js and b.js, the type of abc is (number, number) => boolean

Actual behavior:
Within a.js, the type of abc is (any, any) => void
Within b.js, the type of abc is (number, number) => boolean

The d.ts file is not applied within a module itself, only when it is imported into other files

VS Code Tracked Working as Intended

Most helpful comment

@mhegazy Thank you for the explanation. This makes sense but I can also see @rnemec's point about migration. Is there any way to leverage something like /// <reference ... /> here to explicitly tell TypeScript to use a d.ts file for a module itself?

All 12 comments

I also tried adding /// <reference path="./a.d.ts" /> to a.js but this did not give the correct types in a.js since there is no module import

A .d.ts is a replacement to .js, there is no easy way to map the structure of one to another. if you want to have the types in both, i suggest switching the .js to a .ts`

@mhegazy - while technically, I would agree that it's WAD/WAI, from pragmatic perspective of smooth and incremental transition of JS-only projects to TS, it would be greatly beneficial to be able to define the types and definitions in separate non-production files and utilize the additional knowledge for VSCode/Intellisense, validation, etc.

And today - most of it works (as @mjbvz mentioned), except the module JS file itself (e.g. a.js above).

Again, not challenging "working as intended", but asking for considering extension of the "intended" for practical reasons of JS projects that cannot immediately just switch to TS.

The mapping from a .d.ts to a .js file is not straight forward. There are may patterns in JS that can be used to achieve some of the ES6 declarations. e.g. a class. similarly a module shape in node is not the same as it is in ES6 (and .d.ts).

So given all of that, if you are the author of this .d.ts, consider using JSDoc to annotate your .js file.

@mhegazy Thank you for the explanation. This makes sense but I can also see @rnemec's point about migration. Is there any way to leverage something like /// <reference ... /> here to explicitly tell TypeScript to use a d.ts file for a module itself?

Here is a thought (which may be more on vscode side rather than ts):
VSCode Intellisense is capable of using JSDoc type annotation for resolving the parameter types (and return, etc.) if there are any specified.
I wonder whether that logic can be extended to take .d.ts as an alternative to JSDoc (poor man approach: take the d.ts, internally produce JSDoc and apply it to the module).
But, also, I have no *ing idea how are these designed/implemented. :-)

I could understand the Mohamed's implicated complexity of all possible JS structures in a module (beyond what I asked for) may make it a big project by itself, thus rejected as "too much work and expecting too much bugs and bughancements coming afterwards".

Unless it's worth it considering the number of existing JS projects that cannot move yet (for whatever technical or political reasons).

Enough said - I'll shut up now.

I have a team member that currently prefers not to switch to using typescript due to not wanting a build step. I do enjoy typescript and its associated tooling. I thought that a good compromise would be to use declaration files, but they do not work in their associated JS modules. I would like to use declaration files in their associated javascript file which would very helpful in refactorings and adding features and other maintenance tasks. Here is a (small) example project repo: https://gist.github.com/kaleb/e2f33c5f8ff3bc046a8b430ac8440c27

VSCode output from example repo

A file with a top-level import or export is a module. modules have their own scope, and they do not live in the global scope. This applies to .d.ts files as well. PersonStruct is a declaration within the module person.d.ts and not visible outside except thorough importing.

for this you have two options,

  1. put the declaration in the global scope, yo can do this today by updating your .d.ts
// person.d.ts
declare global { 
    type PersonStruct = PersonStruct;
}
  1. A new feature to add some way to indicate the source of the type for the compiler, that is currently tracked by https://github.com/Microsoft/TypeScript/issues/14377

@mhegazy this is not an understanding about globals. This is a feature request to have a typescript declaration module declare types for a corresponding javascript module inside the module, not creating separate global types. I would prefer to write actual typescript, but I cannot currently. Another option would be to use JSDoc type annotations, but there are a few missing features in typescript JSDoc handling such as the @this tag. The request is to be able to declare a module's types in a separate file and be able to use them in that file as if I were writing in typescript. I just wanted to add my use cases here in case this request ever gets re-opened.

This is a feature request to have a typescript declaration module declare types for a corresponding javascript module inside the module

I understand.. but module scopes have an existing meaning.. merging two module scopes is not something we have done before, and not sure how to reason about that. scopes is a well defied concept for most software developers, and having two files share the same scope is unexpected to say the least.

I just wanted to add my use cases here in case this request ever gets re-opened.

I think the better way to do this is to allow you to define a new module, say person-types.d.ts and then import it some how in your JSDoc. which is tracked by #14377

Was this page helpful?
0 / 5 - 0 ratings