Setting up SystemJS to export TypeScript declarations for an external JavaScript library

I am a beginner in the world of Angular2 and Typescript. I am exploring ways to utilize an external JavaScript library smoothly: I am aware that I can use:

declare var somelibrary: any;
somelibrary.doAnything();

However, I would like to add some typing to it, so I came across the concept of *.d.ts files here.

So, I created a module called chart.d.ts:

export declare class Chart {
    constructor (ctx: any);

    Doughnut(data: any, options: any): Function;
}

(I also tried this approach:)

export declare module 'chart' {
    export class Chart {
        constructor (ctx: any);

        Doughnut(data: any, options: any): Function;
    }
}

and referenced it using various methods:

// version 1
import chartFactory = require('../chart');
// version 2
import { Chart } from '../chart';

and implemented its usage as follows:

// version 1 usage    
new chartFactory.Chart(ctx).Doughnut(this.chart1, {responsive : true});

or for the second import:

// version 2 usage
new Chart(ctx).Doughnut(this.chart1, {responsive : true});

The compilation is successful, but during runtime, SystemJS attempts to load the javascript implementation of my definition by searching for 'path/to/chart.js' (which obviously doesn't exist since the original library was imported through a script tag).

The SystemJS configuration is similar to the one provided in the Angular tutorial:

System.config({
    packages: {
        app: {
            format: 'register',
            defaultExtension: 'js'
        }
    }
});

The tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules",
    "typings/main",
    "typings/main.d.ts"
  ]
}

Any suggestions with explanations on how to resolve this issue?

I believe the problem lies within the setting "module": "system", but the real question is: How can I create internal d.ts without conflicting with SystemJS resolution?

Answer №1

If you are searching for information on ambient modules, you can find more details in the handbook here.

An example of declaring an ambient module (in chart.d.ts):

declare module "chart" {
    export class Chart {
        constructor (ctx: any);
        Doughnut(data: any, options: any): Function;
    }
}

You can use it like this:

import {Chart} from "chart";

let c = new Chart(1);

Keep in mind that the Chart function should be available in the global context.

Instead of creating your own .d.ts files for everything, consider using tools such as typings or tsd.

Answer №2

Utilizing the export of chart.js in a value position, instead of just for its type, can cause issues with TypeScript dependencies when transpiling your module. The loader may not have access to chart.js in this scenario.

To resolve this, I recommend declaring chart.js in your SystemJS config under map or packages, such as 'path': 'path/to/chart.js', and removing the script tag from your code.

If you still need to use a script tag, consider updating your type declaration file to:

export interface Chart {
  new (ctx: any);
  Doughnut(data: any, options: any): Function;
}

You also have the option of configuring SystemJS to load chart.js from a CDN or other source.

Personally, I prefer loading chart.js as a proper module without the script tag. For more guidance on installation, refer to: http://www.chartjs.org/docs/#getting-started-installation

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

Unable to locate partial name

Recently installed the ngx-bootstrap 1.9.2 npm package and encountered an error while trying to compile my Angular project: ERROR in C:/xxx/xx/node_modules/ngx-bootstrap/datepicker/bs-datepicker.component.d.ts (46,15): Cannot find name 'Partial'. ...

Encountering a problem with ng serve while attempting to launch the project

I am completely new to Angular and recently installed the latest version of Node.js along with Angular CLI globally. I cloned a project from GitHub and attempted to run it using 'ng serve', but encountered an error message: https://i.sstatic.net ...

The rxjs package is failing to meet the peerDependencies requirements of its sister packages

After running npm install, I came across this error: npm ERR! Windows_NT 6.1.7601 npm ERR! argv "c:\\Program Files\\nodejs\\node.exe" "c:\\Program Files\\nodejs\\node_modules\\npm\ ...

What is preventing me from getting this typescript plugin to function properly?

Currently, I am working on developing a plugin example and facing an issue. I am struggling to make the module loader recognize that the plugin has additional functionality compared to the original. I believe I am close to a solution, but a little nudge in ...

Using axiosjs to send FormData from a Node.js environment

I am facing an issue with making the post request correctly using Flightaware's API, which requires form data. Since Node does not support form data, I decided to import form-data from this link. Here is how my code looks like with axios. import { Fl ...

When executed through nodeJS using the `require('./main.ts')` command, TypeScript Express encountered an issue with exporting and displayed undefined

Describing my issue is proving to be challenging, so I have simplified the code. Let me share the code below: main.ts import express from 'express'; let a = 1 console.log ('a in main.ts', a) export let b = a const app = express() let ...

Is there a way to automatically extend my content to fill the space on the page below the Material UI AppBar?

I am currently using React and Material UI React to develop my application. My goal is to implement the AppBar component with content underneath, without causing the entire page to scroll. I want the content to occupy the maximum remaining height and the f ...

Tips on navigating an array to conceal specific items

In my HTML form, there is a functionality where users can click on a plus sign to reveal a list of items, and clicking on a minus sign will hide those items. The code structure is as follows: <div repeat.for="categoryGrouping of categoryDepartm ...

The error message "printer.node is not a valid Win32 application" indicates that the

I created a node API for my Angular application that utilizes the node-printer package to print PDF files generated by node. However, when I attempted to run my application using nodemon, an error occurred. Error message: "node printer.node is not a val ...

Steering templateUrl Value Modification on the Go in Angular 2

Looking for a way to dynamically change the template URL at runtime in order to switch between different views rendered in my component. Is there a solution available for this? For example, I want my component to have both grid and list view options, bu ...

What could be the reason for the unavailability of this.state in this particular situation?

In my component, I have defined the following functions: constructor(MyProps: Readonly<MyProps>){ super(MyProps); this.state = {suppliers: [], supplierId:0, supplierName:''}; this.addSupplier.bind(this); } addSupplier(){ ...

Support for the percent sign in right-to-left languages

Imagine you have the following code snippet: <div dir="rtl"> test 50% </div> It currently displays as test 50%. However, according to this wiki page, for Arabic language it should be shown as %50 test, with the percentage sign before the n ...

Mental stability groq fails to provide the requested information

Having difficulty using Groq to fetch data. All other Groq queries work fine, except this one. When manually setting the $slug variable, the data I'm trying to query works with the Sanity Groq VS plugin but returns undefined in my web app. Query: exp ...

What is the best way to retrieve the action parameter in an NgRx effect?

Is it possible to send an action with a parameter and replace the value (9) with (block.id)? this.store.dispatch(RegistryActions.LoadRegistryLayersAction(this.block)); How can I access this parameter in the effect? loadRegistriesLayers$: Observable<Act ...

Using a snippet of HTML code from one Angular component in another component

Is it possible to use a specific div element from one Angular component in another component? main component.html <html> <div1> some elements </div1> <div2> some elements </div2> In the child ...

Failed attempt to install Angular Material

On my Windows laptop, I am currently using the following versions: Angular CLI: 9.1.15 Node: 16.16.0 OS: win32 x64 Windows 10 When I try to add Angular Material using the command ng add @angular/material, it runs without any issues. However, after the i ...

Which programming language or technology utilizes the syntax <%VARIABLE%> and in what context is it employed?

First things first, I want to clarify that I'm not a developer, so this might be a simple question. Despite my research indicating that ASP typically uses this syntax, it's important to note that it is not the case here. I am currently delving i ...

finding the adjacent li element using the document.(property)

Utilizing a pub/sub solution named ably.io for real-time data updates, I have implemented a method that assigns dynamic ids to each ngFor listing. This allows me to easily identify and update the values received from ably.io subscribe. document.getElement ...

Issue with an external library in Angular 2

After generating my Angular 2 library using the yeoman generator and adding it to my main Angular project, I encountered errors when running the app in production mode. The specific errors include: WARNING in ./src/$$_gendir/app/services/main/main.compone ...

Issue: An object with keys {} is not suitable as a React child, causing an error

I am new to TypeScript and seeking help from the community. Currently, I am working on a to-do list project where I am using React and TypeScript together for the first time. However, I encountered an error that I cannot decipher. Any assistance would be g ...