Navigating the world of TypeScript and SystemJS without the confines of Angular

Lately, I've been delving into TypeScript through research and simple "hello world" projects. However, I've hit a roadblock when it comes to using System.js with TypeScript that I just can't seem to overcome. Most tutorials and demos online focus on Angular2, which I'm not quite ready to dive into yet.

For example, my project structure looks like this:

RootFolder
| 
| _lib
| ...... ts (contains .ts files)
|
| components (contains compiled .js files)
| libraries
| ......... systemjs (housing system.js)
|
| index.html
| tsconfig.json

My tsconfig.json file is configured as follows:

{
  "compileOnSave": true,
  "compilerOptions": {
    "noImplicitAny": true,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "outDir": "./components"
  },
  "exclude": [
    "node_modules",
    "wwwroot"
  ],
  "include": [
    "./_lib/ts/**/*"
  ]
}

The TypeScript compiling works smoothly without any issues. I have created a basic class called "Alerter" with the following code:

//alerter.ts
class Alerter {
    showMessage(): void {
        alert("Message displayed.");
    }
}

export default Alerter

In addition, there's an app.ts (the main application file) containing:

//app.ts
import Alerter from "./alerter";

console.log("app.js included & executed");

function test() {
    console.log("test called");
    const alt = new Alerter();
    alt.showMessage();
};

I've tried importing app.js using System.js in index.html and calling the "test" function from the console, but it doesn't seem to work. The initial console.log statement executes fine, but attempting to call test() from the Chrome console returns undefined.

Interestingly, if I remove the dependency on the "alerter" class from my main.ts, everything functions correctly. This is because the compiled app.js only consists of console.log calls and the function definition.

Here are my System.js calls in index.html:

System.config({
    packages: {
        "components": {
            defaultExtension: "js"
        }
    }
});

System.import("components/app");

Feeling rather frustrated at this point, I'm considering reverting back to the simpler days of jQuery. It's frustrating how such a seemingly straightforward task is proving to be so challenging.

Answer №1

It seems like the issue here stems from a combination of TypeScript's export keyword usage and SystemJS.

Based on your explanation, it appears that you are aiming to utilize SystemJS for importing a JavaScript file in a manner similar to using the <script> tag, and then accessing its globally defined functions.

However, it is crucial to understand how TypeScript compiles your files. According to the documentation found at https://www.typescriptlang.org/docs/handbook/modules.html, any file containing a top-level import or export statement is considered a module in TypeScript.

The app.ts file contains an import statement, while the alerter.ts file includes an export statement, which means both will be treated as modules during compilation. Furthermore, your tsconfig.json indicates the use of the system format (though this detail is irrelevant in this context).

A notable advantage of modules is their ability to contain global objects within their scope. Therefore, when you invoke System.import("components/app"), the test() function remains limited to that module. However, by exporting the function, you can call it after the module has loaded:

To achieve this, start by exporting the function:

// app.ts
export function test() {
  ...
};

Subsequently, the System.import() method returns a Promise resolved with the module exports object, enabling the invocation of the test() method within that context.

System.import("components/app").then(function(m) {
  m.test();
});

This approach aligns with your expectations regarding functionality.

If your intention was to define the test() function globally, you must explicitly assign it to the window global object yourself:

// app.ts
function test() {
  ...
}
declare const window;
window.test = test;

Following this adjustment, you can access the function post-importing the package:

System.import("components/app").then(function(m) {
  test();
});

While SystemJS offers various methods for manipulating global objects, leveraging them becomes slightly trickier once imported packages have dependencies that need resolution. You may refer to https://github.com/systemjs/systemjs/blob/master/docs/module-formats.md#exports for potential insights, though this might not directly apply to your scenario.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Typescript polymorphism allows for the ability to create various

Take a look at the following code snippet: class Salutation { message: string; constructor(text: string) { this.message = text; } greet() { return "Bonjour, " + this.message; } } class Greetings extends Salutation { ...

The variable X has been defined, but it's never actually utilized. Despite declaring it, I have not accessed its

I have encountered warnings in VSCode while using certain properties in my Angular component. The warnings state: '_id' is declared but its value is never read.ts(6133) (property) ItemEditComponent._id: number | undefined '_isModeEdit' ...

The error I encountered with the Typescript React <Select> onChange handler type was quite

Having an issue while trying to attach an onChange event handler to a Select component from material-ui: <Select labelId="demo-simple-select-label" id="demo-simple-select" value={values.country} onChange={handleCountryChange} ...

Tips for passing certain optional parameters while excluding others without resorting to undefined or empty values like ""

Is there a way to invoke the function while omitting certain optional parameters without resorting to undefined and empty strings? import { MouseEvent } from "react"; import { DialogType } from "editor-constants"; export interface Dial ...

Is there a way for me to deduce types dynamically?

Is there a way to dynamically infer types, similar to a union type? I am trying to register multiple elements from different parts of the code using a method like registerElement(...), but I am struggling with inferring these new types in TypeScript. This ...

What prevents us from returning Observable.of(false) in the catch block within the canActivate function?

In order to protect certain routes (admin), I utilize the canActivate feature. In this scenario, I employ an authGuard class/function: The issue arises when attempting to return an observable of boolean using: return Observable.of(false);. This approach d ...

Is the runTest.ts class in the vscode-test setup ever utilized in the project? Its purpose remains unclear even in the example project

Being a novice to Typescript, JavaScript, and VScode Extensions I have set up a vscode-test following the guidelines provided here: https://code.visualstudio.com/api/working-with-extensions/testing-extension#custom-setup-with-vscodetest Based on the hel ...

Enhance your Vuex action types in Typescript by adding new actions or extending existing

I'm new to Typescript and I'm exploring ways to add specific type structure to all Actions declared in Vue store without repeating them in every Vuex module file. For instance, instead of manually defining types for each action in every store fi ...

How can I send 'blocking' parameter to getStaticPaths function in Next.js using TypeScript?

Whenever I try to use fallback: 'blocking', in my Next.js page, TypeScript throws an error. I am using the latest 12.2.0 version of Next.js. What could be causing this issue? Type '() => Promise<{ paths: any; fallback: string; }>&ap ...

When attempting to pass props to children, Typescript triggers an error message

I am facing an issue with a component that renders a child based on the specific "league" a user is viewing, such as MLB. Typescript is throwing an error because I am not passing the correct props to the child component. However, the parent component has t ...

Using Angular 4 constructor value in a condition with *ngIf

Within this TypeScript snippet, there is a variable called moreinfo that is initially set to 1. In the constructor, however, the value of moreinfo is changed to 2. Subsequently, based on whether the value is 1 or 2, different div elements are displayed usi ...

openapi-generator is generating subpar api documentation for TypeScript

Executing the command below to generate an auto-generated API using openapi-generator (v6.0.1 - stable): openapi-generator-cli generate -i app.json -g typescript -o src/main/api The json file is valid. Validation was done using openapi-generator-cli valid ...

Using sl-vue-tree with vue-cli3.1 on internet explorer 11

Hello, I am a Japanese individual and my proficiency in English is lacking, so please bear with me. Currently, I am using vue-cli3.1 and I am looking to incorporate the sl-vue-tree module into my project for compatibility with ie11. The documentation menti ...

"Although the NextJS client-side data is present, it seems to be struggling to

I am facing an issue while trying to display fetched data on a blog page. Although the data is successfully retrieved client-side and I can view it using console.log(), it does not appear on the page and the elements remain empty. I am completely puzzled. ...

Error in TypeScript - Anticipated 1-2 arguments, received either none or multiple. Code Issue TS2556

While working in JavaScript, I had no issues with this code snippet. However, when I attempted to implement it in a TypeScript Project, an error surfaced. The problem seems to revolve around the fetch(...args) function call. const fetcher = (...args) =&g ...

Consolidate multiple generic items into a single entry

In my current project, I am structuring the types for a complex javascript module. One of the requirements is to handle multiple types using generics, as shown in the snippet below: export interface ModelState< FetchListPayload, FetchListR ...

The TypeScript datatype 'string | null' cannot be assigned to the datatype 'string'

Within this excerpt, I've encountered the following error: Type 'string | null' cannot be assigned to type 'string'. Type 'null' cannot be assigned to type 'string'. TS2322 async function FetchSpecificCoinBy ...

Decoding enum interface attribute from response object in Angular 4 using typescript

From an API response, I am receiving an enum value represented as a string. This enum value is part of a typescript interface. Issue: Upon receiving the response, the TypeScript interface stores the value as a string, making it unusable directly as an en ...

Determining the data type of a generic variable within an Angular component

I'm currently in the process of developing a versatile component that can handle data of only two specific types: interface X{ name: string, path: string, type: string, } interface Y{ name: string, path: string, } Both types X a ...

After logging out, Next-auth redirects me straight back to the dashboard

In my NextJS application, I've implemented a credential-based authentication flow along with a dashboard page. To handle cases where an unauthorized user lands on the dashboard route, I've created a custom AccessDenied component. In the getServer ...