Can I create definition file for local JavaScript module? - javascript

Let's say I have a a.js file that contains:
export function a() {}
and I want it to import it from the file b.ts (in the same directory) like that:
import { a } from './a.js'
How can I tell TypeScript what the file a.js contains so that compilation of this import succeeds?

What is needed for this to work is typescript definition file named same as JavaScript file (a.d.ts in this case) that contains:
export function a();
It can also specify parameter types, additional exported functions and classes and must use export keyword to indicate what the JavaScript file actually exposes.
One other change is that this JavaScript module needs to be then imported in b.ts as:
import { a } from './a' // without .js
so it takes typescript definition file into account. It will still use implementation from a.js file. It works with webpack too.
If you don't want to describe what's inside a.js and have TypeScript just accept it you can create a.d.ts file like that:
declare var whateva:any;
export = whateva;
Then you can import it like this:
import * as ajs from './a'
and then refer to any function exposed by a.js in your TypeScript files like that:
ajs.a();

You can just simply use a statement:
declare var a:any;
(after the import) in this same file you are using the a (i this case in b.ts). Thanks to this the TS compiler will not complain. Also your IDE will not shown the errors.

Related

How to import all default types in a TypeScript Definition file?

Current situation (simplified):
type OneCtrl = import("some-package").default.OneCtrl
type TwoCtrl = import("some-package").default.TwoCtrl
declare module "my-package" {
export function useUtils(options: OneCtrl): TwoCtrl
}
I am having to repeatedly import individual types from the default import.
Using <reference> didn't work.
I tried type g = import("some-package").default and then using g.OneCtrl but that didn't work either.
I am importing from a package that has a namespace. Direct ES6 imports would result in the definition file not being an ambient definition anymore which is what I need otherwise the project gives errors.
Environment (For Context): Vite + Vue 3 + TS Project
Update on specifics
I am trying to add types to this external package vue-grapesjs-composables which is based on the original grapesjs package which does have types.
What I mean by having tried ES6 imports is that this would work in the definition file:
import type grapes from 'grapesjs'
declare module "vue-grapesjs-composables" {
export function useGrapes(editorConfig: grapes.EditorConfig): grapes.Editor;
}
but gives this error when I import it in a component:
Could not find a declaration file for module 'vue-grapesjs-composables'

Referencing vanilla js file in TypeScript getting file is not a module

I'm trying to import a file into TypeScript that's basically just a js file that you'd put into a tag. I've tried a few different things.
// global.d.ts
declare module 'myfile.js'
Inside of the react file:
// component.tsx
import { foo } from '../lib/myFile.js' // This is saying it is not a module
Inside of the js file, it looks like this a few times so not sure how I need to reference the file:
(function( something ) {
something.Foo = function (){}
}(window.something = window.something || {}));
Any thoughts on how I could use this file? Do I need to go through and declare typings for everything in it?
EDIT: I've added allowJS to my tsconfig but it still doesn't work.
You can only import what is exported from the file.
If your file contains only immediately invoked functions, or top level code, you only need to import the file itself like this:
import '../lib/myFile.js'
This is a little weird, however. I would suggest wrapping everything with a function and exporting then importing that function instead.

webpack js file scope - import functions file

I am learning to use webpack for first time. I am really stuck with something that was never a problem with gulp, that is the way it scopes different files.
I have a file that contains multiple standalone functions (helpers.js).
function a() {
}
function b() {
}
function c() {
}
Based on my reading here do I need to import each function separately? How do I import the whole file?
From the example in link:
a.js:
export var a = 4;
b.js
import { a } from "./b.js";
var b = a+1;
console.debug(b);
I suspect that you have used some concatenation plugin for gulp and your scope was "shared".
With ES6 modules, you have to define exactly what functions to export and import because the scope of each file is separate.
So in your example, we can do it this way:
Create default export in helpers.js and define what data to export.
helpers.js
function a(){}
function b(){}
function c(){}
export default {a,b,c}
And import data this way:
import myHelpers from 'helpers'
Then to use helper a, you will need to call myHelpers.a()
Another approach is to create "named" exports
helpers.js:
export function a(){}
export function b(){}
export function c(){}
To import all data use:
import * as myHelpers from 'helpers'
Then similar to the previous example, call -> myHelpers.a()
But typing "myHelpers" is not always convenient, so here we can use named exports additional benefit - you can import it by a name, so we can do it like this:
import {a,b,c} from 'helpers'
Then you can call a()
You have to type all the names you want to import. There is no "shortcut" for that.
Why this way?
better control on what exactly you import to your code, optional "tree shaking"
no conflicts between imported modules
Webpack - ProvidePlugin
Ok, but what if you use those helpers really often? Do you need to import them everywhere? Technically - yes. But Webpack can automate that for us, have a look on Webpack - ProvidePlugin which automatically loads modules instead of having to import them everywhere.
For Webpack 3, if you go with the first solution it will look like this:
new webpack.ProvidePlugin({
helpers:['path/to/module/helpers', 'default'],
}),
That will make helpers available like a "global", and you will be able to use helpers.a()

Adding external javascript to Ionic 2 project

Lets say I have this foo.js file where I declared a variable, a function and a class.
It is not in the project yet.
Now assume I want to use this variable, class and function in my home.ts method, or just make it globally available (to use in a home.ts method).
How can I make it happen?
lets say in your foo.ts file we have a funtion
myfunt(){
//your logic goes here
}
now if you want to make use of this function in home.ts file the
step1: import your foo.ts file in home.ts
step2: in your export class should look like this
export class home extends foo {
//since you have used extends keyword now you unlocked all the data in foo.ts file for home.ts file
//here now try to access your myfunt() funtion
constructor(){
super.myfunt(); //user super keyword to access all the data available in foo.ts file
}
}
You can use definition files (.d.ts).
First, check if foo.js have already a definition file created by the community. Check it here:
http://microsoft.github.io/TypeSearch/
or here https://github.com/DefinitelyTyped/DefinitelyTyped
If it exists you can install it like this:
npm install --save #types/foo
If not, you can create your own definition file for this javascript file.
Let call it foo.d.ts with a content like this:
declare var data:any;
declare function myFunc(n:string);
Once you have it you can use it like a normal ".ts" file.
import * as foo from "./foo"; //"./foo" is the path of your .d.ts.
foo.myFunc()
More information here:
https://blogs.msdn.microsoft.com/typescript/2016/06/15/the-future-of-declaration-files/

How should I define a global TypeScript variable in a definition file so that it can be imported?

I have an external JS library with a global parameter:
function Thing() { ... }
...
var thing = new Thing();
There is a TypeScript definition file, so in thing.d.ts:
declare var thing: ThingStatic;
export default thing;
export interface ThingStatic {
functionOnThing(): ThingFoo;
}
export interface ThingFoo {
... and so on
Then I import this into my own TS files with:
import thing from 'thing';
import {ThingFoo} from 'thing';
...
const x:ThingFoo = thing.functionOnThing();
The problem is that transpiles to:
const thing_1 = require("thing");
...
thing_1.default.functionOnThing();
Which throws an error. I've asked about that in another question, and the suggestion is to use:
import * as thing from 'thing';
That doesn't fix it - it gives me thing.default in TS but then that's undefined once transpiled to JS.
I think there's something wrong with thing.d.ts - there must be a way to define a typed global parameter that can be imported.
How should I write thing.d.ts so that it represents the JS correctly and doesn't transpile to include default or other properties not actually present?
If the only way to use that library is by accessing its globals (as opposed to importing it as node module or amd or umd module), then the easiest way to go is have a declaration file without any exports at top level. Just declaring a variable is enough. To use it, you have to include that declaration file when compiling your typescript code, either by adding it to files or include in tsconfig.json, or directly on command line. You also have to include the library with a <script> tag at runtime.
Example: thing.d.ts
declare var thing: ThingStatic;
declare interface ThingStatic {
functionOnThing(): ThingFoo;
}
declare interface ThingFoo {
}
test-thing.ts
const x:ThingFoo = thing.functionOnThing();
can be compiled together
./node_modules/.bin/tsc test-thing.ts thing.d.ts
the result in test-thing.js:
var x = thing.functionOnThing();
See also this question about ambient declarations.
Note: there are module loaders out there that allow using global libraries as if they were modules, so it's possible to use import statement instead of <script> tag, but how to configure these module loaders to do that is another, more complicated question.

Categories