Can Typescript import CommonJS Modules? - javascript

I had this file:
//foo.js
var foo = function () {
return "foo";
};
module.exports = foo;
So, I wanted to import it to my Typescript file. I tried this
//typescript.ts
import * as foo from ("./foo");
Didn't work. I read about this 'ambient' modules, so I added this
//typescript.ts
/// <reference path="./foo.d.ts" />
import * as foo from ("./foo");
And I added a "foo.d.ts" file in the same folder, which had the purpose of letting typescript know about the types of my imported function:
declare module "foo"
{
function foo(): string
export = foo;
}
No luck.
I thought that the problem was with the import syntax (you cannot have the same syntax for es6 and commonjs modules, right?). So I did this.
import foo = require("./foo");
As you might guess, that didn't work either.
I have been able to import d3 an use it successfully when I installed it as a node module with npm install d3 and referenced its d.ts file. I did it with this code:
import * as d3 from "d3";
I haven't been able to do the same with any other module (jquery, box2d, box2d-commonjs, among others), nor with my own libraries as demonstrated above. I am new to Typescript, so probably I'm missing something very obvious, but I haven't been able to figure it out by myself.

Turns out it was something really obvious: you had to use the --allowJs option. This worked for me:
tsc --moduleResolution "node" --module "commonjs" --allowJs main.ts
Though, I still can't figure out why d3 worked while the others libraries didn't.

Related

Import JS web assembly into TypeScript

I'm trying to use wasm-clingo in my TypeScript React project. I tried to write my own d.ts file for the project:
// wasm-clingo.d.ts
declare module 'wasm-clingo' {
export const Module: any;
}
and import like this:
import { Module } from 'wasm-clingo';
but when I console.log(Module) it says undefined. What did I do wrong?
Notes:
clingo.js is the main js file.
index.html and index_amd.html are two example pages
Solution:
I solved the problem like this:
// wasm-clingo.d.ts
declare module 'wasm-clingo' {
const Clingo: (Module: any) => Promise<any>;
namespace Clingo {}
export = Clingo;
}
and
import * as Clingo from 'wasm-clingo';
Here's the source for this solution
I know you found a solution acceptable to you; however, you don't really have any types here, you just have Module declared as any, which gives you no typescript benefits at all. In a similar situation I used #types/emscripten, which provides full type definitions for web assembly modules compiled using emscripten. You simply need to do:
npm install --save-dev #types/emscripten
then change your tsconfig.json types array to add an entry for emscripten.
After that you can just write Module.ccall(...) etc. If you like you could of course write const Clingo = Module and then make calls against that if you want a more descriptive name than Module (which is a terrible name!).
You're welcome ;)
I think the issue is that wasm-clingo exports the module itself but import { Module } from 'wasm-clingo' expects a property.
Try
import Clingo_ from 'wasm-clingo';
const Clingo: typeof Clingo_ = (Clingo_ as any).default || Clingo_;

How do we declare import types from NPM library that has no declaration files?

For example, if I have the following in my app,
import Node from 'infamous/motor/Node'
console.log(Node)
that works just fine. But the moment I actually do something with it,
import Node from 'infamous/motor/Node'
console.log(new Node)
then TypeScript will complain because there's no type definition for Node. How do I define the type of Node?
The library has no type declarations of it's own. I tried something like
import MotorNode from 'infamous/motor/Node'
declare class MotorNode {}
console.log(' --- ', new MotorNode)
but I get the error
./src/app.tsx(6,8): error TS2440: Import declaration conflicts with local declaration of 'MotorNode'
When I need to do what you are trying to do, I create an externals.d.ts file in which I put module augmentations for my project and make sure that my tsconfig.json includes it in the compilation.
In your case the augmentation might look something like this:
declare module "infamous/motor/Node" {
class Node {
// Whatever you need here...
}
export default Node;
}
I put it in a separate file because a module augmentation like this has to be global (must be outside any module), and a file that contains a a top-level import or export is a module. (See this comment from a TypeScript contributor.)

TypeScript: Can I mix using "import * from" and "require(*)"

Is it ok in TypeScript to mix these too 'include' types?
import { SomeType, someFunc } from "./MyThings";
And:
import events = require('events');
The first would be a TypeScript module with an export or two... and the second is just a node module called events (I guess this could be anything pulled in from NPM too).
Am I ok to mix these two conventions in a single TypeScript file?
Yes, this is acceptable in TypeScript.
When using the import foo = require('foo');, you must have a module 'foo' declared with declare module 'foo', typically in a .d.ts file.
This is typically covered in node.d.ts.

import from ES6 module to legacy js code

I use babel.js and have a new module foo in my code
foo.js:
export function foo(number) {
return number + 42;
}
And bunch of big old files where everything is global. And I need to call a foo function from that legacy code.
bar.js:
...
var result = foo(0);
...
But I can't just import foo cause then my bar.js will be a module and unavailable from other old code. Is there a way to import module
and retain my bar.js global?
I had a somewhat similar problem recently. I ended up polluting window object with everything I need in legacy code.
I created separate register.js module for this purpose and included it to my webpack build:
import ClassA from './ClassA'
import ClassB from './ClassB'
import * as utils from './utils'
Object.assign(window, utils)
Object.assign(window, {ClassA, ClassB})

How to import a js library without definition file in typescript file

I want to switch from JavaScript to TypeScript to help with code management as our project gets larger. We utilize, however, lots of libraries as amd Modules, which we do not want to convert to TypeScript.
We still want to import them into TypeScript files, but we also do not want to generate definition files. How can we achieve that?
e.g. The new Typescript file:
/// <reference path="../../../../definetelyTyped/jquery.d.ts" />
/// <reference path="../../../../definetelyTyped/require.d.ts" />
import $ = require('jquery');
import alert = require('lib/errorInfoHandler');
Here, lib/errorInfoHandler is an amd module included in a huge JavaScript library that we do not want to touch.
Using the above code produces the following errors:
Unable to resolve external module ''lib/errorInfoHandler''
Module cannot be aliased to a non-module type.
This should actually produce the following code:
define(["require", "exports", "jquery", "lib/errorInfoHandler"], function(require, exports, $, alert) {
...
}
Is there a way to import a JavaScript library into TypeScript as an amd Module and use it inside the TypeScript file without making a definition file?
A combination of the 2 answers given here worked for me.
//errorInfoHandler.d.ts
declare module "lib/errorInfoHandler" {
var noTypeInfoYet: any; // any var name here really
export = noTypeInfoYet;
}
I'm still new to TypeScript but it looks as if this is just a way to tell TypeScript to leave off by exporting a dummy variable with no type information on it.
EDIT
It has been noted in the comments for this answer that you can achieve the same result by simply declaring:
//errorInfoHandler.d.ts
declare module "*";
See the github comment here.
Either create your own definition file with following content:
declare module "lib/errorInfoHandler" {}
And reference this file where you want to use the import.
Or add the following line to the top of your file:
/// <amd-dependency path="lib/errorInfoHandler">
Note: I do not know if the latter still works, it's how I initially worked with missing AMD dependencies. Please also note that with this approach you will not have IntelliSense for that file.
Create a file in lib called errorInfoHandler.d.ts. There, write:
var noTypeInfoYet: any; // any var name here really
export = noTypeInfoYet;
Now the alert import will succeed and be of type any.
Typically if you just want to need a temporary-faster-solution, that could be done by defining a new index.d.ts in the root of the project folder, then make a module name like described inside package.json file
for example
// somefile.ts
import Foo from '#awesome/my-module'
// index.d.ts on #awesome/my-module
declare module '#awesome/my-module' {
const bind: any;
export default bind;
}
Ran into that that problem in 2020, and found an easy solution:
Create a decs.d.ts file in the root of your TS project.
Place this declaration:
declare module 'lib/errorInfoHandler';
This eliminates the error in my case. I'm using TypeScript 3.9.7

Categories

Resources