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

Importing untyped JS modules #3019

Closed
jonrimmer opened this issue May 4, 2015 · 25 comments
Closed

Importing untyped JS modules #3019

jonrimmer opened this issue May 4, 2015 · 25 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@jonrimmer
Copy link

I have been trying out the 1.5 beta, but I am confused about importing modules from 3rd-party JS libraries. As I understand it, TS is intended as a superset of JS so if, for example, I have a CommonJS library called foo.js, then in my app.ts, I should be able to do:

import foo from 'foo';

And this should be compiled (depending on my compile options) into a CommonJS require statement, which can then be consumed by Node, Browserify, etc.

This works in regular JavaScript (as compiled by Babel), but it does not work in TypeScript. I get a compiler error saying "Cannot find external module 'foo'".

I understand that I can maybe write a .ts.d file that describes this library, but what if I don't want to do this? What if I just want to import a module and use it, as I would in regular JS?

@igl
Copy link

igl commented May 4, 2015

Just doing let foo = require('foo') worked for me.
Not perfect but at least i see which modules need definitions later on.

@tinganho
Copy link
Contributor

tinganho commented May 4, 2015

You need to declare a d.ts file. I think let foo = require('foo')will break intellisense support.

@mhegazy
Copy link
Contributor

mhegazy commented May 4, 2015

The TypeScript compiler needs to know the shape of your import to ensure any uses of the import are correctly typed. consider this:

import foo from "module";
foo.a = 1;    // does foo has an export "a", and if so is it really a number

The compiler can not just look into the .js file, cause the .js file does not have any type annotations and thus most inferences will degenerate to any, which is not that helpful.

Instead, you need a different means to tell the compiler the shape of the module, its exports, and their types. that is the .d.ts as @tinganho mentioned earlier.

There is a community repository of definition files (.d.ts) for popular libraries on http://definitelytyped.org/; If your library is not there, you can hand edit a .d.ts file for it following this wiki page or use a tool like closure-ts that is d.ts generator from JSDoc typings.

@mhegazy mhegazy added the Question An issue which isn't directly actionable in code label May 4, 2015
@MicahZoltu
Copy link
Contributor

I believe @jonrimmer and I both are wanting to know how to silence that error, perhaps with some kind of #prgama in the file? This is particularly meaningful for transitioning projects from ES6 to TypeScript.

Given the example import foo from "module";, I want a way to tell the TS compiler that I know there is no type definition for this and I accept that foo will be any. Maybe something like proposed here: #2709 (comment)

import foo: any from "module"; This would allow me to silence the warning while I work on migrating my project over to TypeScript. When I have an actual d.ts or ts file to work with, I can remove the : any. Even better would be if TypeScript gave me a warning if it was able to find module and it turns out that foo is not any. This way, while migrating I would have the safety of the static analyzer yelling at me if I forgot to remove the : any from any of my imports.

@mhegazy
Copy link
Contributor

mhegazy commented May 4, 2015

@Zoltu i believe this is fair. #2709 tracks this and should be simple to add.

@danquirk danquirk closed this as completed May 4, 2015
@zakhenry
Copy link

zakhenry commented Jun 5, 2016

FYI #2709 has been superseded by #6615

@alcfeoh
Copy link

alcfeoh commented Dec 14, 2016

This article brings great solutions to the problem: https://www.stevefenton.co.uk/2013/01/complex-typescript-definitions-made-easy/

@MicahZoltu
Copy link
Contributor

I have been out of the TypeScript for a while, but at the time I participated in this discussion Definitely Typed didn't solve the problem primarily because it was unversioned. It was way too easy to pull in a definitely typed TSD only to find out (after 4 hours of debugging) that the definition it provided didn't match the definition of the version of the library you were using. Also, the tooling (again, at the time) wasn't very good in the browser world when it came to keeping TSDs and dependencies in sync.

@sjatkins
Copy link

In what sense is Typescript a mere superset if it forces me to create type files for all my pre-existing javascript modules? The easy interoperability is basically a lie. This is especially so for modules I have only minified versions of.

@mhegazy
Copy link
Contributor

mhegazy commented Feb 27, 2017

In what sense is Typescript a mere superset if it forces me to create type files for all my pre-existing javascript modules? The easy interoperability is basically a lie. This is especially so for modules I have only minified versions of.

Why does it "force" you?

@alcfeoh
Copy link

alcfeoh commented Feb 27, 2017

@mhegazy If you don't declare those types, it won't compile. Try using any third-party JS in a TypeScript project and you'll see how it goes. Most developers end up declaring everything as "any" in the typings file just to make TypeScript happy.

@mhegazy
Copy link
Contributor

mhegazy commented Feb 27, 2017

There does not seem to be any coercion involved here. the compiler needs to know that a name or is just a typo. No requirement to add declaration files to all your existing code. as a matter of fact, an import to a module with no .d.ts file will just result in an any automatically.

You can add declarations as you go, depending on where your project is at:

  • declare var $: any -- anything goes, i would recommend using this when you are starting your project
  • Adding more structure: declare var $: (...args)=> JQuery;, I would recommend doing this as you go on with your project, and want to get stronger checks.
  • Using @types for known packages, or contributing to DefinitelyTyped for not known ones.

@sjatkins
Copy link

sjatkins commented Feb 28, 2017

Force in the sense of perfectly good node modules having problem if just imported in TS unless I do a type file or, as I understand it so far, if I include it directly in my index.html and perhaps do a declare var thing.. What I lost was simple module import in ES6 world from such modules. I miss it. This is in a webpack using project and more specifically an Angular2 one.

Of course it is possible I am missing something simple such I am on week two of fighting with typescript for first time.

@mhegazy
Copy link
Contributor

mhegazy commented Feb 28, 2017

Force in the sense of perfectly good node modules having problem if just imported in TS unless I do a type file

This should not be the case. import foo from "foo" checks that there is a file called node_modules\foo\index.js (or any other file following the node resolution at runtime), and if one exists you get no error. the type of foo is any though. but no need to add a declaration file unless you want to tighten your types.

If you have a sample I would be happy to look at.

@alcfeoh
Copy link

alcfeoh commented Feb 28, 2017

@mhegazy The issue really arises when you use a Javascript package that requires use of "new" or some kind of constructor function. For instance, epub-js requires to create an instance like this:

var Book = ePub("url/to/book/");
Book.renderTo("area");

TypeScript required me to create typings in order for this to work. A strict superset of Javascript with optional typings should be totally fine with the above code.

@mhegazy
Copy link
Contributor

mhegazy commented Feb 28, 2017

ePub here is a global variable and not a module import. you need to tell the compiler that there is a name calledePub, so that it does not warn you if you misspell it e.g. epub`.

So you will need to add, in just one location, declare var ePub: any;.

A strict superset of Javascript with optional typings should be totally fine with the above code.

A super set means that your JS code is valid TS code. and that is the case, the typescript compiler will
produce JS output that looks identical to your input (modulo white spaces). You still get errors that ePub is not a known identifier. you could choose to ignore the errors. but that also means that other places where you have typos are not flagged.

@sisiea
Copy link

sisiea commented Mar 27, 2017

@mhegazy
I use package named 'react-lazyload' in typescript.Then I get an error!

here is my code:
import LazyLoad from "react-lazyload"

when I use webpack to bundle my code ,I get an error:
" error TS2307: Cannot find module 'react-lazyload'."

@mhegazy
Copy link
Contributor

mhegazy commented Mar 27, 2017

I am using TS 2.2 and i am not seeing this error. what version are you using?

@balajikris
Copy link

@mhegazy

I'm still observing this behavior with TS 2.2.1 and VSCode

import d from "adal-node";

tsc.exe: 'Could not find a declaration file for module 'adal-node'. 'e:/proj/node_modules/adal-node/lib/adal.js' implicitly has an 'any' type.'

I see all linked bugs are closed. Is this expected to be working now?

@mhegazy
Copy link
Contributor

mhegazy commented Apr 5, 2017

Yes. Please file a new issue and provide a self contained reproduction of the issue.

@balajikris
Copy link

thanks, filed #15031

@PhotoAtomic
Copy link

PhotoAtomic commented Jan 5, 2018

i solved by just prepending //@ts-ignore right before the untyped module import
it is clear that from that point on you are in god's hands....
but it is dead easy and solves me a lot of headache in no time

for example (for font-awesome 5):

//@ts-ignore
import fontawesome from '@fortawesome/ fontawesome';
//@ts-ignore
import regular from '@fortawesome/ fontawesome-free-regular ';

fontawesome.library.add(regular);

plus, it works with webpack :)

@s50600822
Copy link

it is clear that from that point on you are in god's hands....

God has nothing to do with this :trollface:

@mhegazy
Copy link
Contributor

mhegazy commented Feb 5, 2018

//@ts-ignore disables error reporting for a specific line. it does nto address the issue. TS already has a way to define a module, add declare module '@fortawesome/ fontawesome'; in your project and you should not be getting this error.

@ackvf
Copy link

ackvf commented Apr 27, 2018

I have a SFC that implements .defaultProps, that are of course not recognized by TypeScript. This makes gradual transitions from js to ts impossible. The component is impossible to use in TS.

export default function Spinner({centered, color, size, thickness, padding}) {
  return ( <>...</> )
}

Spinner.propTypes = {
  centered: PropTypes.bool,
  color: PropTypes.string,
  padding: PropTypes.oneOfType([
    PropTypes.number,
    PropTypes.string
  ]),
  size: PropTypes.oneOfType([
    PropTypes.number,
    PropTypes.string
  ]),
  thickness: PropTypes.number
}

Spinner.defaultProps = {
  centered: false,
  color: '#0d83ff',
  padding: 0,
  size: 20,
  thickness: 0.6
}

ts reports

[ts]
Type '{}' is not assignable to type 'IntrinsicAttributes & { centered: any; color: any; size: any; thickness: any; padding: any; }'.
  Type '{}' is not assignable to type '{ centered: any; color: any; size: any; thickness: any; padding: any; }'.
    Property 'centered' is missing in type '{}'.
(alias) function Spinner({ centered, color, size, thickness, padding }: {
    centered: any;
    color: any;
    size: any;
    thickness: any;
    padding: any;
}): JSX.Element
import Spinner

Is there a way to override the default generics in React.Component?
Is there any conditional logic that can be used for generics within the react/index.d.ts file? I would be happy to create a PR.

@microsoft microsoft locked and limited conversation to collaborators Jul 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests