Support looking for modules under node_modules when importing
chanon opened this issue ยท 138 comments
Update 5 November 2015
The functionality requested below is currently implemented in typescript since at least 1.8 with one main difference:
Instead of having typescript.main
and typescript.definition
properties, there is only one typings
property which you can point to either a d.ts
file or a normal .ts
file.
If you're developing a module to just use locally, you can have the typings
point to a .ts
file, but if you plan to publish the module, it is recommended to have it point to a d.ts
file. This is because you don't want your module consumers to recompile your module files, just consume its typings.
I have setup an example of using this here:
https://github.com/chanon/typescript_module_example
There is a documentation page here that has more information:
http://www.typescriptlang.org/docs/handbook/typings-for-npm-packages.html
Thank you TypeScript devs and all contributors.
Original issue / feature request follows
Motivation
In TypeScript it is a lot harder to re-use typescript modules compared to re-using npm modules in JavaScript.
It would be beneficial if the typescript compiler is smart enough to look in node_modules folders and package.json files.
The reason is so that npm module developers that use TypeScript might be able to start writing and distributing modules through npm itself. TypeScript would be able to piggyback on npm's infrastructure and wide support.
Example for node_modules
If we had:
./node_modules/concator/index.ts
./myApp.ts
And in index.ts we had:
export function concat(param1: string, param2:string): string {
return param1 + ' ' + param2;
}
in myApp.ts:
import concator = require('concator'); // loads the module from node_modules
var result = concator.concat('I like', 'this.');
var wontWork = concator.concat('this will fail'); // compile error, concat needs 2 params
So basically, the compiler is smart enough to find the module in node_modules and it automatically uses the typescript version (index.ts).
Then when the code is compiled to JavaScript, it naturally uses the JavaScript version.
Importing Folders as Modules
A more basic case is supporting Node.js's popular rule of http://nodejs.org/api/modules.html#modules_folders_as_modules as suggested by @vvakame below and in the closed (semi-duplicate) #207 issue.
typescript.main in package.json
There could be an addition to package.json files to specify where the main .ts file of a TypeScript npm module is. This would be similar to the main
key that specifies where the main JavaScript / .js file is but for TypeScript instead.
Eg package.json for an npm module named "myModule" located at node_modules/myModule/package.json
{
"main": "./dist/index.js",
"typescript": {
"main": "./src/index.ts"
}
}
In this example node_modules/myModule/src/index.ts
would be the main TypeScript file and doing an import myModule = require("myModule");
would import the node_modules/myModule/src/index.ts
file.
For a JavaScript coder writing var myModule = require("myModule");
in a JavaScript file, the require would load the node_modules/myModule/dist/index.js
file as usual.
As can be seen in this example, the TypeScript src is in the node_modules/module-name/src
folder and the compiled JS files would be in node_modules/module-name/dist
.
Something like this could be a (semi) standard for TypeScript npm modules so that the TypeScript source is cleanly separated from the compiled JavaScript output.
A more basic case as suggested by @vvakame below is supporting the popular Node.js rule of http://nodejs.org/api/modules.html#modules_folders_as_module
typescript.definition in package.json
Another possible key for package.json for non-TypeScript (plain JavaScript) npm modules could be typescript.definition
. This would point to a .d.ts file that defines the module for TypeScript users of the npm module.
So that an
import $ = require('jquery');
would automatically read a jquery.d.ts
file defined in the typescript.definition
key in jQuery's package.json and make $
the correct type.
Example format:
{
"main": "./dist/index.js",
"typescript": {
"definition": "./index.d.ts"
}
}
(This format is already used by tsd as @Bartvds explains below.)
Then us TypeScript coders would just have to try to get as many non-TypeScript npm module maintainers to merge our pull requests that have our .d.ts files and package.json typescript.definition
keys.
If we succeed with that, then TypeScript coders' life would be bliss ... no more separate managing of DefinitelyTyped .d.ts files. Just npm install and you get your TypeScript definitions too! Automatically and up-to-date with the module version installed.
List of Benefits
What we get from all of this is
- npm modules can be written in TypeScript.
- Both TypeScript and JavaScript coders can use these modules
- The module users who use TypeScript get the benefits of static typing without the module coder (or user) having to use the usual method of writing (or generating) separate .d.ts files (so when the sourcecode of the module is already in TypeScript we don't have to have another .d.ts file to maintain)
- There would be a way to easily re-use and distribute TypeScript modules using npm which everyone is already familiar with
- It could help promote TypeScript usage itself, as JavaScript coders who use the npm modules written in TypeScript might see how nice / better the TypeScript source is and try switching to it. Or they might want to contribute to the module and since the source is in TypeScript they would have to learn it which may lead to them liking it and deciding to use it in their own projects.
- Basically it would help grow the TypeScript community through all the code sharing that could result. Right now everyone's TypeScript code is mostly their own / in their own silo. This is actually probably an extremely important thing as not having a proper/easy way to share/distribute/re-use modules is probably limiting the growth of the language. [1]
- Re-use of modules in internal projects would be a lot less of a hassle and would reduce the need for all those relative paths to .d.ts files and relative paths in module requires, and general .d.ts stuff. (Right now when writing TypeScript code, I find I have to learn to be good with counting ../../ s)
- This approach also supports Browserify/Webpack as Browserify/Webpack also look under node_modules, so this allows for easy reusable / npm distributed TypeScript modules for both the server and browser
- Non-TypeScript npm modules can easily be used in TypeScript with type information through the
typescript.definition
key addition. This allows .d.ts definition files to be packaged together with the npm module so that updating an npm module will automatically update its .d.ts definition file. This removes the need to update .d.ts files manually. - Using definition files through the
typescript.definition
is simpler because it is simply animport moduleName = require("moduleName")
statement with no need for a separate///<reference ...
- Using definition files through the
typescript.definition
should also allow the use of different versions of the module in the same code base without type names clashing.
Detailed Proposal
@Nemo157 has written a very detailed proposal for how all of this should work at:
Proposed TypeScript Require Resolution Semantics
https://gist.github.com/Nemo157/f20064a282ee620f3877
An addition in the proposal is the usage of /typings
folders which can hold definition files that can be automatically managed by tools such as tsd
for JavaScript npm modules that won't include definition files in their repositories.
Final Supporting Facts
Since TypeScript compiles to JavaScript which runs mainly in two places: node.js and in browsers, supporting node_modules is beneficial to both places (practically all of where TypeScript is used) because of npm and Browserify/Webpack.
ie. there is no reason to come up with a different scheme when node_modules is what all TypeScript users use already for maybe 75%-100% of all their JavaScript code. (Taking out 25% for maybe RequireJS users.)
Footnotes
[1] - BTW I see there is a NuGet package manager (?) from Microsoft that can distribute typescript modules (?), but coming from a node.js focused (non .NET focused) background, I don't see NuGet becoming widely used outside of Microsoft focused shops, especially as npm is the standard for node.js and is a leading standard for client side JavaScript too. If I didn't use TypeScript I would have never heard of NuGet. The average node.js / client side JavaScript coder would probably prefer using npm, the same tool they use already rather than having to use something Microsoft specific such as NuGet. (I don't actually know a thing about NuGet so what I'm saying here might not actually matter.)
[moved to typescript.main in package.json in the issue description above]
๐
I think http://nodejs.org/api/modules.html#modules_folders_as_modules is very popular rule of Node.js.
other example.
./test/index.ts
export function hello() { return "Hello, world"; }
./main.ts
import test = require("./test/");
console.log(test.hello()); // print "Hello, world"
[moved to typescript.definition in package.json in the issue description above]
One solution would be to solve it with better tooling. E.g. import foo = require('foo')
gives you a hint to look for some local node_module+package.json (foo is a ts project) or DT definition (foo is a js project where library authors don't want to maintain the ts def).
FYI; I'm actually testing something similar to this in TSD; a way to expose & link definitions that are bundled in the npm (or bower) packages.
It's in my dev version for 0.6, and it works by adding a typescript
element to the package.json (or bower.json), with a sub element definition
(a sub element because maybe one day there'd be source
too, or whatever).
{
...
"main": "./index.js",
"typescript": {
"definition": "./foo.d.ts"
}
...
},
Then you can run a command on TSD, currently tsd link
and it will scan all package.json files in node_modules (or bower or whatever), find that property if defined and add a reference to it to the central tsd.d.ts
bundle in your project.
@Bartvds That's pretty nice. Could be the first step for having .d.ts in npm packages. I like the package.json structure with "definition" in "typescript", it's a lot more organized.
If TypeScript compiler itself could read it automatically, would be very cool.
Tagging this for discussion -- smarter external module resolution is something we need to talk about to understand the various scenarios here. This was brought up previously and we made a few tweaks in 1.0.
Also discuss #207 - looking under 'index'
Yep, the issue is immensely important even for browsers - lots of projects use browserify/packify and therefore node-compatible directory layouts
๐
There's been some work already in this area back in the codeplex repo, one pull request by leebyron and one by kayahr.
I've been meaning to try and port one of them to the new repository, but it seems the related code has been re-arranged a lot.
I have written a proposal for how to add this to the TypeScript compiler. This also includes looking in the typings
directory as that will be important when working with javascript modules that will not maintain their own typescript definitions. Unfortunately to make this all work transparently with tsd
will still take a little work as the requirement of /// <reference
d files being ambient external declarations makes things a little hairy. I will take a look at implementing this on a branch and providing some example modules using it.
Looks sensible. Will this cover modules with clashing type dependencies? I mean if an app imports A and B, and B is also dependent on A. It's easy to fall into duplicate type errors if there are two copies of the external declarations.
It shouldn't, they should resolve to different external module names so declare identically named independent types in different modules. The structural type checking should then allow the different modules to interact without issues.
That's one of the major issues with the current tsd
definitions that this is trying to resolve, by defining external ambient modules there is no way for them to handle having multiple versions of a library with identically named, but slightly different types.
@joewood also there will be troubles between different versions of A
app
โโโ A@2.0.0
โโโ B@1.0.0
โโโ A@1.0.0
there is no way for them to handle having multiple versions of a library with identically named, but slightly different types.
interested to hear solutions to the same. TypeScript has a global
level variable scope for ambient declarations
Even if the versions match, at the moment I see issues with two different, but matching ambient declaration files causing duplicate symbol errors. The locally defined /// reference
directive needs to somehow resolve back to a single file. Either that, or the type identity needs to include the path and structural typing will take care of version mismatches etc..
@joewood Yep, that's what I hope will be fixed in the majority of cases by changing require
to load the correct definitions, avoiding /// reference
wherever possible. The external modules will be identified by their absolute paths instead of having ambient declarations, so loading multiple of the same name from different paths and at different versions should be possible.
Yep, that's what I hope will be fixed in the majority of cases by changing require to load the correct definitions, avoiding /// reference wherever possible.
๐
๐
I've done an initial implementation of my proposal along with creating an example set of modules to show that all the different ways to make a module will work. Including using different versions of the same library in different sub-modules.
๐
Folders as modules with index.ts ๐
๐
๐
๐
๐
๐ ๐ ๐
๐ ๐ ๐ ๐
Commenting to bump this back onto our radar.
I've had good success with @Bartvds's suggestion :
Then you can run a command on TSD, currently tsd link and it will scan all package.json files in node_modules (or bower or whatever), find that property if defined and add a reference to it to the central tsd.d.ts bundle in your project.
So definitely consider supporting typescript
in package.json
as that's the way community has gone.
We definitely need tsc to be aware of the node_modules
folder if TypeScript is going to be widely used in the node.js community. I currently use symlinks to modules that are part my development project (using npm-workspace), and I have two options at the moment:
- import directly from node_modules, which looks wrong:
import Foo = require("node_modules/mymodule/Foo");
- get tsc to generate the declaration files and then stitch them together using a manually maintained module declaration file that switches over the string module names
Could tsc check the external module name in import declarations and then during path resolution also apply node_modules
in the same manner that the node.js runtime does? A compiler option could also turn this on or off.
๐ ๐ ๐
Could tsc check the external module name in import declarations and then during path resolution also apply node_modules in the same manner that the node.js runtime does
This is how it should be. The current manner of just looking up the directory tree to find a file with the said name bares no resemblance to JS execution contexts.
This has been on my list for a while now. will try to get this in the next release.
We (Booktrack) use TypeScript for all our web development, and we face similar challenges to the node.js developers. I speak up because the voice of web devs doesn't seem as loud as that of the node devs.
Solutions (in order of worst-for-us to best-for-us):
- resolution of top-level external module names via hard-coded lookup into
node_modules
- no control over resolution of top-level external module names
- a compiler flag to control the optional resolution of top-level external module names into the
node_modules
directory - a compiler "module search path(s)" parameter to control the optional resolution of top-level external module names into the given path(s)
- a compiler "module resolver" parameter to provide the compiler with a JS plugin that will resolve all (not just top-level) external module names
- appropriate hooks into language services such that the external module name resolution is controllable
Option 1 is terrible, I'd rather option 2.
Option 5 and 6 would allow for exotic uses of import statements, such as those found when working with requirejs or webpack plugins. The basic idea: the compiler delegates all external module name lookups (not just top-level) to a third-party (a plugin or callback). The delegate, given the path to the module under compilation and the external module name, returns to the compiler the filesystem path OR the type information for the given module name.
I'd be happy if option 4 was implemented, delighted if option 6 was implemented and over-the-moon if both option 4 and option 6 were implemented.
How about a --basePath for your module search root, all module imports will be looked relative to that path. This only applies for AMD.
I think the node issue is much simpler, we just need to implent it:)
Note that we actually got an implementation (and tests) from @Nemo157 here long ago #247 (comment)
Agree with @mark-buer and @mhegazy, option 4 a search path should be a simple fix. A more elaborate solution in the language service (option 6) is definitely required longer term.
Worth adding: this alone won't fix the TypeScript reuse issue in npm because of the duplicate symbol issue for common type references #1125. We really need to avoid /// <references... by using .tsconfig files and get this fixed properly by bundling packages into a single external typed module as suggested in #17
Another vote for getting the node_modules folder recognised by the typescript compiler.
For CommonJS modules, typescript should ideally be following the same filename resolution that require.resolve does (as outlined by the psuedocode on this page: http://nodejs.org/api/modules.html#modules_all_together.
this functionality is critical to allow integration of the typescript compiler into other node packagers, such as browserify. @Nemo157 's patch does a fine job, but it doesn't allow for easy testing with existing packagers as most have moved on to later versions of typescript and are no longer compatible with his code
Where does the node_modules
directory have to be relative to the sources?
Atom-TypeScript now supports typescript.definition
out of the box. Details : #2829
You can also create such packages easily using atom-typescript ๐น again see #2829
Limitation
It will work flawlessly if you share a package that doesn't depend on any external libraries. If it does then we need a module conflict resolution algorithm.
I am open to suggestions for this case, but my plan is:
- we do some smart stuff in reading such a
d.ts
not giving TypeScript the externalreference
comments (e.g. node.d.ts here https://github.com/TypeStrong/atom-typescript-examples/blob/master/node/node_modules/example-typescript-b/definition/sample-b.d.ts) And instead pointing to our own.d.ts
if we have it in our Typings.
Is this going to stay on track for 2.0? It seems like kind of an important feature for Node.js adoption, which right now is painful, even with DefinitelyTyped and the likes.
It seems like kind of an important feature for Node.js adoption, which right now is painful, even with DefinitelyTyped and the likes.
@LPGhatguy Please see #2338. @vladima is working on it but don't think its been assigned any milestone yet ๐น
@LPGhatguy we are trying to get this in the next release. hopefully soon.
Then, why does it tagged as TypeScript 2.0 as a milestone?
thanks @heycalmdown, removed the milestone. we do not usually tag milestones to suggestions. hopefully we have an update within a week or so on this issue. stay tuned.
I would like to chime in asking for ES6 module support to follow this as well (which I assume it would?)
Typings for
import mylib = require('mylib');
mylib.foo(mylib.bar);
should behave the same as
import { foo, bar } from 'mylib';
foo(bar);
I would like to chime in asking for ES6 module support to follow this as well (which I assume it would?
@DavidSouther That would automatically be the case. The lookup between the two is consistent ๐น
If I'm using nightly, starting tomorrow I should expect importing node modules to "just work"?
Question:
I think it is a common convention to have files named
"index" in commonJS and
"main" in AMD
for short paths.
In the question on top the author imports
/node_modules/concator/index.ts
as
import concator = require('concator');
Please forgive me - I am currently figuring out if also the index resolution is supported now and how about index.ts or main.ts in AMD requires` resolution?
I am also pinging @basarat to know if it is / will be supported by https://github.com/TypeStrong/atom-typescript because now it does not allow me to require any index.ts as mentioned above.
@sebilasse, if you are using typescript@next
today, this should work with --module commonjs
import concator = require('concator'); // resolves to node_modules/concator/index.ts
There are not changes to how AMD resolution from previous releases.
@DavidSouther it should be in typescript@next
today. give it a try and let us know how it fares.
@sebilasse, for AMD i think we need to do something as noted by @vladima in #2338 (section for: RequireJS/ES6 module loader).
Very nice!! \o/
@mhegazy Still not working quite as I expect.
I put together https://github.com/DavidSouther/typescript-example-using-node with my "ideal" use case. tslib is a simple library that exports a single function. tsclient depends on tslib, as well as readline
from the Node packages. The setup script is a convenience to install, link, and execute. I've included a run, and annotated the unexpected portions with inline comments.
% ./setup
...
> tslib@0.0.0 build ~/ts-node/tslib
> tsc --version ; tsc -p src/
message TS6029: Version 1.7.0-dev.20150831
...
> tsclient@0.0.0 build /Users/southerd/devel/tmp/ts-node/tsclient
> tsc --version ; tsc -p src/
message TS6029: Version 1.7.0-dev.20150831
# Expect this to find tslib, but fail type checking.
# See tsclient/app.ts for details
src/app.ts(4,21): error TS2307: Cannot find module 'tslib'.
+ node ./dist/app.js # This works as expected!
What would you ask? What is the meaning of life?
42
+ set +x
I am also not getting language support for tslib imports in tsclient (VSCode Version 0.7.0 (0.7.0)), though I am not entirely sure which TSC it's using, or how to change that.
@DavidSouther TypeScript compiler check 'typings' field in package.json to find '.d.ts' files. With this change I'm getting src/app.ts(13,7): error TS2322: Type 'string' is not assignable to type 'number'.
which looks like a legitimate error
Ah, I must have missed that piece of docs. I'm still having the second issue - how do I change the VSCode tsc version?
you can provide custom TypeScript SDK location to VSCode via "typescript.tsdk"
setting - it should point to the folder containing tsserver.js
and standard '.d.ts' files. In case if TypeScript is installed as npm package it will be something like
// Place your settings in this file to overwrite the default settings
{
"typescript.tsdk": "C:\\Sources\\bugs\\node\\typescript-example-using-node\\tslib\\node_modules\\typescript\\lib"
}
Did anyone get a sample working ? I tried the whole afternoon to play with this, but I always end up with
error TS2307: Cannot find module
At the moment the code is in node_modules/my-module/. And I defined an index.ts that takes care of exporting everything, and I referenced it in the package.json under typescript.main. In the consumer project I tried import {AClass} from 'my-module'; and import my-module = require('my-module'); They both lead to the same error with typescript 1.7.0-dev.20150901.
When resolving a module with non-relative name, with --module commonjs
, the compiler will look for a .d.ts
that matches the name in node_modules\name\index.d.ts
or look in package.json
for a property typings
, and load the .d.ts it points to.
from your description, looks like you are setting it to index.ts
, you do not really want to compile your dependencies, you just want to consume their typings, so you should set it to index.d.ts
instead.
I've updated steps in node module resolution algorithm to reflect the implementation: #2338
@DavidSouther I have the exact same problem apparently. When I compile with a dependency in node_modules it can't resolve the module and outputs an error, but then, it still generates the js, and if I run it, it runs. Maybe it's due to my setup I don't know. My d.ts is mostly empty, I have an index.ts that takes care of importing and reexporting all the classes of my modules defined in many .ts files. And then my d.ts file just references this index.ts and exports everything from index.ts like this :
/// <reference path="index.ts" />
declare module 'my_module' {
export * from 'index';
}
Also, it somehow still compiles the ts from node_modules, therefore I should add a clean task to delete it after compilation. Is there a description of the feature somewhere that sums up the process ?
edit: I got it to work, but it's super hacky and still outputs errors. I created a d.ts with dts-generator, and then I imported my classes like this :
import MyClass from '../../node_modules/my_module/dist/MyClass';
If I use import MyClass from 'my_module/MyClass' I get it to compile without error, but at runtime I get the error cannot find module 'my_module/MyClass'. With the above solution it points directly to the compiled .js and at runtime it works somehow, even though it outputs the error cannot find module at compile time.
Still having issues importing from submodules (eg npm install angular2, import { Inject, Binding } from 'angular2/di'
. Will work on getting a contained test case up tonight.
Don't think that angular already bundles its typings in the way expected by TypeScript compiler.
That's likely true; I'll work with them and see where it ends up.
this feature is working well on typescript 1.1 , for example https://github.com/Nemo157/typescript_w_node_modules_example
but fail in typescript 1.5.3 , anything changed ?
------ update ---------
I know it will release in 1.6 , thanks
I can only get this "half-working" in 1.6.2
First, I package a library with a my-lib.d.ts
in the dist
directory, and points to this file in the package.json
file typings
attribute (e.g. "typings" : "dist/my-lib.d.ts"
)
Then I import this library in a Test.ts
TypeScript file using
import { MyObject } from "my-lib"
MyObject
is properly imported and the js code is emitted on transpilation.
Visual Studio Code even provides completion on MyObject
However I get compiler warnings that:
Test.ts(10,60): error TS2306: File '[]/node_modules/my-lib/dist/my-lib.d.ts' is not a module.
Visual Studio Code will actually show the import as a hard error
Any imported modules from a node package need to be "external modules" and not "ambient module declarations". i.e. no declare module "foo" {.. }
declarations, but rather, top level import or export declarations in the file.
So if your package "my-lib" is written in typescript, just build it with --declarations
and set the typings to the .d.ts
file of your main module. if not, and your typings are something you hand authored, or got from definitely typed, then you will need to either change it to an external module, or wait until #4665 is resolved (hopefully soon).
The reason of this restriction is this can cause global scope pollution and conflicts later on for your package users. there is a long discussion about this in #4665.
Here is some documentation for future searches: https://github.com/Microsoft/TypeScript/wiki/Typings-for-npm-packages
@mhegazy Thank you for your quick reply which really helped in my quest to automate the build of commonjs librairies, written in Typescript, which can be consumed by both Javascript and TypeScript code.
import/export
syntax and resolution has been moving so fast recently that what I guess is missing right now is a definitive guide on how to build one.
I got it working... with one caveat (and hence another question)
Here is a simplified view of the setup.
The library consists of three objects A1, A2 and B in 2 typescript files A.ts and B.ts; something like
sources
A.ts
class A1{}
class A2{}
export { A1, A2 }
B.ts
class B{}
export { B }
What we want to expose is collected in an index.ts
:
export * from './A'
export * from './B'
build
The build is conducted with the help of grunt and the --module commonjs
and --declaration
flags are set on tsc
1.6.2
The end result of the build is a tree that looks like
mylib
package.json
dist/
js/
A.js
B.js
index.js
typings/
A.d.ts
B.d.ts
index.d.ts
package.json
contains these two entries:
"main": "dist/js/index.js",
"typings": "dist/typings/index.d.ts"
Using this library in TypeScript 1.6.2 with a simple import {A1, A2, B} from "mylib"
works absolutely fine. Multiple level dependencies (i.e. librairies importing each other) works fine too.
Where problems arise is when the library depends on another library which is not a TypeScript library.
Say the library depends on Node.js.
In one of the source files there will be a reference to the typings of NodeJS e.g.
///<reference path="../typings/node/node.d.ts"/>
Upon transpilation that <reference >
instruction is going to end up in the corresponding declaration file; the problem is that the path to node.d.ts
is likely to be wrong or inexistent.
Is there a recommended way to go about this ?
Note: this problem is alleviated by the use on an index.ts
file to expose the interesting parts of the library, since index.ts
has no reason to contain a <reference >
instruction and with 1.6.2, the compiler does not seem to care that A.d.ts has invalid path in the reference instruction
@bgrieder We handle this in Phosphor using tsconfig.json
:
https://github.com/phosphorjs/phosphor-widget/blob/master/src/tsconfig.json
We simply add any external typings we need to the compiled files. This does mean that if any of those external types are part of our public interface, the consumers of the code will also need to provide those external typings as part of their build. This is okay. If we were to bundle those definitions, and some other lib used by the consumer also bundled those same definitions, there would be duplicate symbol conflicts.
@sccolbert Yes !
I was worried that removing <reference ...>
instructions would break auto-completion on all IDEs, but hey, no: at least Visual Studio Code 0.8.0 seems to be smart enough to pick those definitions from the tsconfig.json
file ! (after a restart)
Done with reference
. Excellent !
What if you are using a plain Node.js
project within it and *.d.ts for it, how does the tsconfig
solution help you?
@heycalmdown you just add the d.ts
to the files
field on the tsconfig
, here's an example which does that:
https://github.com/phosphorjs/phosphor-widget/blob/master/test/src/tsconfig.json#L11
https://github.com/phosphorjs/phosphor-widget/blob/master/test/src/index.ts#L10
Note that we have to use require
here instead of import
only because of how the d.ts
file for expect.js is written internally.
Okay, I got it. Your repositories look like a kind of a good example.
Has this actually been implemented in TypeScript 1.6.2?
If it has, can somebody tell me what I'm doing wrong here?:
https://github.com/chanon/typescript_module_example
You probably want the es6 import syntax.
On Wed, Nov 4, 2015, 6:10 AM chanon notifications@github.com wrote:
Has this actually been implemented in TypeScript 1.6.2?
If it is, can somebody tell me what I'm doing wrong here?:
https://github.com/chanon/typescript_module_exampleโ
Reply to this email directly or view it on GitHub
#247 (comment)
.
I've just updated it to use the es6 import syntax and I still get the same errors (cannot find module).
@chanon the package.json
for node_modules
packages need to have a typings
key which points to a d.ts
file, not a typescript
key pointing .ts
files like you have now.
We use node modules resolution in PhosphorJS exclusively (on TS 1.6.2) and it works fine. Here's an example: https://github.com/phosphorjs/phosphor-widget/blob/f908341cb1d46ada8ad8149e695a75e7ea2fde57/package.json#L6
Thank you @sccolbert, however my initial proposal (at the top of this issue) was to allow for a typescript.main
property in package.json
which would point to the main TypeScript entry point for node module packages written in TypeScript.
This would allow for importing TypeScript modules in TypeScript code without the need for d.ts
typing files (there would be no need to even generate them).
@sccolbert I see thanks.
Can someone who knows tell me if I should create another issue requesting this specific feature?
Main related issues to module resolution logic (other than this one) seem to be #2338 which is closed and #5039 which seems to be about supporting SystemJS style path resolution which looks very complex.
However just simple CommonJS style importing like initially requested in this issue seems to have been forgotten? At least the part about typescript.main and folders as modules?
I don't understand the need of having (and desire to have) d.ts files if both the module and the module consumer are already written in TypeScript.
It's actually not much different from importing a TypeScript file relatively ex.
Instead of having to do:
import * as lib from '../relative/path/to/typescriptFile.ts'
Or:
import * as lib from '../../node_modules/myModule/index.ts'
Just let TSC be able to find the typescript file to import using normal node_modules path resolution. And at least allow for importing folders as modules (with an index.ts) so that in the second example I could do:
import * as lib from 'myModule'
Or is it because of "you do not really want to compile your dependencies, you just want to consume their typings"?
@chanon the behavior you outline is what is in master now. can you give typescript@next
a try?
the original implementation of #2338 added some extra checks to ensure it is a .d.ts, and that is mainly for the reason you mentioned. you do not want your package users to compile your "sources" on every compiler invocation, and get different output based on their compiler options, you only want to share your typings.
However if you are building both packages you might want to do that while iterating on them. The restriction was removed in #5278.
Please take a look at the wiki page for sharing typings through npm package for more information: https://github.com/Microsoft/TypeScript/wiki/Typings-for-npm-packages
@mhegazy Just tried with typescript@next
, works as expected!
This is great!! Thank you!!!
And thank you everyone for participating in this and related issues ๐
I've added an update to the issue text above to explain the way this feature has actually been implemented.
At risk of stepping into a minefield, how is this expected to work with plain-old npm modules that don't have a typings
property in package.json? Trying to use either tape
or get-parameter-names
with typescript@next
causes it to blow up in my face as it is unable to find those packages due to the fact they don't have that property.
Sure, they are not typescript modules, but I can't seem to find a work around and that locks out a significant portion of the npm ecosystem.
@danpantry Usually you would use a normal .d.ts file written specifically for that module. The DefinitelyTyped project has .d.ts files for lots of common modules. There is a tsd utility that can help install and manage .d.ts files from DefinitelyTyped for you.
You can use normal modules without typing by just using the normal commonjs require syntax.
eg
var moduleName = require("moduleName")
@chanon feels like a bit of a hack to use the 'classic' require
syntax when using the ES6 syntax with TypeScript so I can use JavaScript dependencies, but thank you. I have heard of the tsd utility but I am unsure of how that would factor in to using ES6 imports.. unless I have to start using /// <reference path=...
for these sorts of modules?
Yes that is one way. Another way is to us tsconfig.json files and put your root tsd.d.ts file as the first file.
You may also be interested in reading this, covering tsd and typings https://angularclass.com/the-state-of-typescript-packages/
@joewood thanks for the info, last time I looked into typescript was in the days of individual .d.ts
files. excellent article