Consuming JavaScript code in TypeScript application - javascript

I'm learning TypeScript and as a practice I wanted to try to consume JavaScript code in my TS app.
For example, this is your .js file:
foo = function() {
console.log("imported from Test.js");
};
I have managed to make it work with the following code:
//Test.js
module.exports.foo = function() {
console.log("imported from Test.js");
};
//Test.d.ts
declare module 'Test' {
export function foo(): void;
}
//HelloWorld.ts
import * as t from './Test';
t.foo();
This code executes fine but produces the following error which I cannot get rid of:
Error:(1, 20) TS2306:File 'C:/Users/2512/Projects/TypeScript/Test.d.ts' is not a module.
Also, if module.exports is used in Test.js then foo() cannot be called in Test.js as foo(); as it produces a foo is not defined error.
My main question is, what is the most up-to-date practice to import .js code into .ts without making any modification to an existing .js file?
I've spent many hours looking for the answer but could not find an ideal solution. Thank you.
P.S. I have typings installed in the project so I believe /// <reference path="Test.d.ts" /> is not required in Test.ts.

Related

cannot use import statement outside a module - Excel custom functions add-in: proper way to use JS functions defined in taskpane.js in functions.js

Newbie here in Office add-ins and JavaScript, so please be patient!
I created a Javascript Excel custom functions add-in, by using the Yeoman generator. In one of my custom function I want to use a JS function defined in an external file. So I defined a function named testExternal and placed it in taskpane.js file:
export function testExternal() {
return 1;
}
then in the functions.js file I have:
import { testExternal } from "../taskpane/taskpane.js";
and in my custom function:
console.log(testExternal());
When debugging, I'm getting the desired 1 in console, but also get the "Cannot use import statement outside a module" error message:
This happens not only in debug mode, but also when the add-in is published on a web server and the add-in is sideloaded. So the external defined function is working correctly, but:
is there any way to get rid of that error message?
what are the steps to use a function defined in another JS file (not in taskpane.js)? Let's say I want to have all my utils functions in a file named utils.js and use that in my custom functions. What is the best location for utils.js and how can be automatically added to the dist folder, when the project is build in VS Code?
Thank you for your time,
Adrian
javascript + html :
If you are using native javascript "for browser" (I'm mean it's not a node application that use packages, etc...).
When you import a script where you need to use import statement you need to set his type as module :
<script src="app.js" type="module"></script>
utils.js
function foo() {
return 'Hello';
}
export { foo };
This one is a module :
app.js
import { foo } from 'utils.js';
node.js :
If you want want to use ES Modules you have to set the property type of your package.json as module :
package.json
{
"type": "module"
}
If office add-in doesn't allow you to use ES Modules you have to use Nodes modules to import / export things :
utils.js
function foo() {
return "Hello";
}
module.exports = foo;
// or
module.exports.foo = foo
Then :
const foo = require('utils');
// or
const { foo } = require('utils');

Correct way to export/define functions in Electron's Renderer

I have a JS file that I'm importing into my Electron's "main" (or background process), app.js, using require (eg: const myJS = require("./pathToMyJS/myJS");)
Contents of myJS.js:
module.exports = {
mFunc: function mFunc(param1) {
...
}
};
And I can use mFunc in app.js as myJS.mFunc(param1); & everything's great.
Then, I tried to follow the same process for the "renderer" JS. So my renderer.js now imports const myOtherJS = require("./myJS/myOtherJS"); where this other JS file follows the exact same module.exports logic as myJS.
And the root HTML (app.html) declares the renderer as <script defer src="./renderer/renderer.js"></script>.
But on launch, I get:
Uncaught TypeError: Cannot set property 'exports' of undefined
at renderer.js? [sm]:34
Searching online, I came across this answer that mentions that the AMD way could be used instead of the commonJS way. So I tried the following: (not sure whether this is syntactically correct!)
define(
["renderer"],
function rFunc(param1) {
... }
)
But that fails with:
Uncaught ReferenceError: define is not defined
So what's the correct way to have functions defined for export when using them in the renderer? What I've been doing so far is just to write the functions in their own JS files (eg: function func1() { ...}) & declaring all of these files in the app.html as <script defer src="./funcFile1.js"></script>.
Turns out, I was just exporting incorrectly. modules.export was the point of failure as modules is undefined on the renderer.
Instead, if I do the following to export individual functions:
// ./myJS/myOtherJS.js
export function rFunc() { ...}
And then import into my renderer.js like:
import { rFunc } from './myJS/myOtherJS';
rFunc();
Things work as I originally expected.
This Google Developers Primer on modules was useful in understanding the concepts.
AMD is not provided by node.js by default. It's used by Require.js and other FWs. Here is a link on how you can use it with node:
https://requirejs.org/docs/node.html

Why is my function causing a TypeError <function> is not a function?

I am calling a function that appears to obviously be a function, but I keep getting TypeError: [function name] is not a function.
Here is a minimal example to reproduce the error.
main.ts
import someFunction from './someFunction'
export const baseUrl = document.location.protocol + '//' + document.location.hostname
someFunction(); //causing TypeError: someFunction is not a function
someFunction.ts
import {Foo} from './Foo'
export default function someFunction(): void {
//some code here
let foo = new Foo();
//some other code here
}
Foo.ts
import {baseUrl} from './main'
export class Foo{
constructor()
private someRandomPrivateFunction(): void {
//some code
let url = baseUrl + "other/stuff"; //removing this line fixes the TypeError
//some other code
}
}
Some details on the background items being used.
Typescript is 1.8 targeting ES5, and generating modules using AMD.
RequireJS is 2.2.0 and data-main points to main
I was testing in Chrome 52.0.2743.116 m
This took me way too long to figure out, but eventually it boiled down to a circular reference.
In Foo.ts if the reference to baseUrl is removed, then everything else works fine because baseUrl is a dependency coming from main.ts
To fix the problem, baseUrl just needed to be moved to a different file baseUrl.ts
Some painful lessons drawn from this experience:
Nothing should be dependent on main.ts... that one should have been obvious.
The error messages spawning from a circular reference can be very vague, completely unrelated, and several layers away from the actual problem, so don't depend on error messages to avoid circular dependencies.

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

TypeScript - Module is undefined at runtime

I dont understand what i'm doing wrong. I've create a TypeScript project in VS2012, and created a file named "Vector.ts", in a sub-directory named "Physics":
// Module
module Physics {
// Class
export class Vector {
constructor(public x: number) { }
}
}
Also, I have the following app.ts file:
/// <reference path="Physics/Vector.ts" />
window.onload = () => {
var vector = new Physics.Vector(6);
};
The project is successfully compiled, but when i launch it, i get the following exception:
0x800a1391 - JavaScript runtime error: 'Physics' is undefined
I don't understand what am i doing wrong...
Thanks.
If you are using AMD style modules with a module loader such as Require.Js, you need an import statement. See Steve's accepted answer here: https://stackoverflow.com/a/14919495/1014822 Your code will look something like:
import Physics = module("Physics/Vector");
var vector = new Physics.Vector(6);
... and you won't need this: /// <reference path="Physics/Vector.ts" />
If you are not using a module loader, you just need to make sure you include your Vector.js output file somewhere in your html page, and make sure it loads before your app file. In this case, you use /// <reference path="Physics/Vector.ts" /> to tell TS where to find your module for intellisense etc. to work.
Just for completeness, if you're using System then you'd use the import function:
System.import("Physics/Vector");
If you're doing this for Angular 2 then you'd want to do this before your bootstrap import

Categories

Resources