What is the meaning of empty export {} in vanilla javascript/HTML - javascript

In the Google Maps Javascript API example, I see they had something like this in the HTML:
<script type="module" src="./index.ts"></script>
and an empty export statement at the end of the TS/JS scripts.
let map;
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
center: { lat: -34.397, lng: 150.644 },
zoom: 8,
});
}
window.initMap = initMap;
export {};
I don't see any examples or mentioning of empty exports on MDN, so I was wondering if anyone knew how it works. How does the script know to run it if the export is empty.

This looks like something in TypeScript; it has nothing to do with JavaScript.
If either of the cases below occurs, then you will need an import/export in the file.
The TypeScript file is being called with the flag below.
--isolatedModules
The tsconfig.json file has the following key and value.
{
"isolatedModules": true
}
According to typescriptlang.org, it states:
If isolatedModules is set, all implementation files must be modules (which means it has some form of import/export). An error occurs if any file isn’t a module.
If you try to run the TypeScript file with the --isolatedModules flag, you get an error like below.
'index.ts' cannot be compiled under '--isolatedModules' because it is considered a global script file. Add an import, export, or an empty 'export {}' statement to make it a module.
As the error states above, the simplest way to fix the issue without adding any unnecessary import statements and/or export statements, it is easiest to export an empty object ({}), like so.
export {};
In summary, the empty object export will not do anything in JavaScript (or TypeScript, without the --isolatedModules flag). However, it comes in handy when running with the --isolatedModules flag.
The Google Maps JavaScript API example might be getting ready for this scenario, in case someone copied-and-pasted the code, so that they wouldn't get an error.

Related

TypeScript Augmenting Window not working in separate files

I'm looking to add another property to window. I can do that with this:
// global.d.ts
import { IConfig } from './src/models';
export {};
declare global {
interface Window {
_env: IConfig;
}
}
But then when I try to reference this new property in a different file, it complains:
// src/util.ts
// Property '_env' does not exist on type 'Window & typeof globalThis'.
export const URL = `https://example.com/${window._env.path}`;
But when I combine these into the same file, everything is fine and there are no errors. Is there anyway I can have these in a separate file?
I'm using TypeScript 4.1.2.
I went down a bit of a rabbit hole but found this relevant documentation
I was able to accomplish this exactly as you have written (different type of course) in an existing angular 8 project and svelte project using their existing polyfills.ts files for my global declaration.
Are you sure you tsconfig.json is compiling everything correctly?

New eslint errors with the #typescript-eslint/no-unsafe-* rules

I'm having some trouble with adding them into some existing projects. For example, I have a class in a module that I developed:
export default class ClassName {
// Class members
}
Now I import that into another project:
import ClassName from 'modulename';
const object = new ClassName();
I get 2 errors on this line.
On the object in const object:
error Unsafe assignment of an any value #typescript-eslint/no-unsafe-assignment
On the new in new ClassName:
error Unsafe construction of an any type value #typescript-eslint/no-unsafe-call
How can I avoid these errors?! I would really like to be able to follow these rules because I think they'd be so useful!
Thanks.
Here's another example:
import { readJsonSync } from 'fs-extra';
const testEnv = readJsonSync(testEnvPath);
Here I get the no-unsafe-assignment error on the testEnv of const testEnv, and the no-unsafe-call error on the readJsonSync call on the second line.
I can get rid of the first one with this code:
interface ITestEnv {
// interface members
}
const testEnv: ITestEnv = readJsonSync(testEnvPath) as ITestEnv;
however, I still can't figure out how to get rid of the second one on the readJsonSync call.
ESlint can not resolve the absolute import of your module,
which makes it to infer your class type as any.
Make sure baseUrl and paths in tsconfig.json file used by ESlint are defined correctly.
#see Typescript – Module Resolution
In the first case, you have just one error coming from the constructor, which is cascading to the const assignment. Something in your class implementation is making the type-inference to be inferred as any.
Not saying your code is incorrect. It might be, but there's an (open issue on Github) reporting a constructor as being incorrectly flagged by the same rule.
On your second issue, have you added #type/fs-extra as a project dependency? Many npm packages do not have types themselves. Types are created by someone and added to the #types library. When that's the case, the #types/package_name must be added as a dependency separately.

How to share a typescript function from a react project with a common html website?

I want to share a complex typescript exported function to a simple HTML - javascript website
I tried to use npm tsc to transform the file into javascript, but generated files have "exports" functions that creates errors in the browser console.
myFunction.ts
export const getTest = (test: any) => {
// Change test object
return test;
};
generated myFunction.js
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTest = function (test) {
// Change test object
return test;
};
Browser console actually warning me "Uncaught ReferenceError: exports is not defined" when I try to include the file with a script tag in HTML file.
What am I doing wrong?
In order to use the original myFunction.ts file all you need to do is this:
Remove the typing and change the extension to .js:
export const getTest = (test) => {
// Change test object
return test;
};
And then, in your HTML file's <script> tag for that JavaScript file, make sure you set the type attibute to module like so:
<script type="module" src="myFunction.js"></script>
Finally, you'll need to import that functionality where you intend to use it.
That should do it as long as you consider browser compatibility:
ES6 Modules
To make this ultimately clear, here is a Plunkr to demonstrate what I mean.
The export keyword creates a module, which can only be used with a module system (such as webpack).
Either use a module system or drop export to create a normal file that creates global names.

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

Typescript Error Putting Classes in Separate Files

I feel like this is a really basic mistake I'm making, but I can't find the solution anywhere. I have two classes, Moo.ts:
module namespace {
export class Moo{
constructor() {
// window.console.log("hello from Moo");
var foo:Foo = new Foo();
}
}
and Foo.ts:
module namespace {
export class Foo{
constructor() {
// window.console.log("hello from Foo");
}
}
When running Moo.ts I would expect it to make an instance of Foo, but it doesn't. It give this error:
TypeError: namespace.Foo is not a constructor
It works fine when I put the two classes in the same ts file, but when I break them up everything falls apart. Am I missing something?
You probably included the Foo.js (The generated file) in your html after Moo.js, this means that when Moo.js run (As it was the first js file) it did not find namespace.Foo
The order of including the generated js files is important. That's why you'd better use the tsconfig.json and include one generated js file in your html (You can use source-maps to debug the TypeScript code)

Categories

Resources