Achieving VS Code/typescript autocomplete functionality without the need to import the library

When a module (for example, moment.js, knockout, or big.js) is added with a <script> tag like this:

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.js">
</script>

that defines a global property (for instance, moment, ko, Big, etc.), how can one access/declare the types on window (or global) in Typescript?

For instance,

const x = moment()
const t = ko.observable()
const b = new Big()

How can one set the ambient type of these globals without including the entire moment.js library? The goal is to have properly typed global references for use with VS Code, tsc, ts-loader, or babel-typescript.

In the case of moment, the types are found at node_modules/moment/moment.d.ts, but for other libraries (like knockout or big.js), they are located at @types/[module]/index.d.ts.

This seems like a common issue, yet there isn't a clear guide on how to achieve it.


Here is an example tsconfig:

{
    "compilerOptions": {
      "target": "ESNext",
      "moduleResolution": "node",
      "allowJs": true,
      "noEmit": true,
      "strict": false,
      "isolatedModules": false,
      "esModuleInterop": true,
      "noResolve": false,
      "baseUrl": ".",
      "paths": {
        "*": [
          "*",
          "js.packages/*"
        ]
      },
      "jsx": "preserve",
      "outDir": "dist/"
  },
  "include": [
    "js.packages/**/*.ts",
    "js.packages/**/*.tsx",
    "js.packages/@types/lib.d.ts",
  ],
  "files": [
    "services/app/src/entry.js"
  ],
  "exclude": [
    "node_modules"
  ]
}

Here's an example of lib.d.ts:

declare global {
  type Bigable = Big | string | number
  interface Window {
    Big: typeof import('big.js'),
    moment: typeof import('moment'),
    Sentry: typeof import('@sentry/browser'),
  }
}

and here's how consumption should work:

const v = new Big(1)
const m = moment()
const s = global.Sentry()
const o = ko.observable()

Which may result in red underlines in VS Code indicating errors:

https://i.sstatic.net/dAiPk.png

Knockout works because @types/knockout/index.d.ts contains:

declare var ko: KnockoutStatic;
declare module "knockout" {
    export = ko;
}

I have declared a global Big on interface Window similarly.

Unfortunately, Sentry and moment (in this situation) do not seem to function correctly, and it's uncertain what steps need to be taken to resolve this issue.

Answer №1

To import types in TypeScript, you should use the import keyword and declare your variables in the global scope instead of on the Window object. Although assigning keys to Window creates global variables, TypeScript does not recognize them as such. It is better practice to directly declare your variables in the global scope.

declare global {
  export var moment: typeof import('moment');
  export var Sentry: typeof import('@sentry/browser');
}

const m = moment();
Sentry.init({}); // The documentation suggests that calling Sentry() directly may not work as expected

Answer №2

The topic at hand is not particularly restricted to any specific platform, but I will explain how I go about incorporating moment in Angular.

Initially, it is advisable not to load the script from a URL. Instead, use npm install moment to place it in your node_modules directory. This way, it will be included in the minified version of your application. While optional, this method is highly recommended.

"scripts": [
          "node_modules/jquery/dist/jquery.slim.min.js",
          "node_modules/moment/moment.js",
           ...
        ]

Regardless of the aforementioned step, once the script is linked in your tsconfig (or angular.json), you can easily use it with the following line at the beginning of the file:

import * as moment from 'moment';

I personally prefer employing this syntax for most libraries that involve an object, such as shortid, linq, and lodash.

Some libraries function more effectively with declare var statements. For instance, jQuery seems to perform better in that manner.

declare var $

Autocomplete

If you seek autocomplete functionality, make sure to have a .d.ts file loaded for the respective library. The npm package for moment includes one, but other libraries may require an additional npm package installation for this purpose (e.g., @types/lodash, @types/jquery).

Visual Studio Autocomplete relies on .d.ts files to recognize types. You can find instructions on configuring this feature in the documentation here. It might also be feasible to adjust the configuration as mentioned towards the bottom of the page.

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

Unleash the power of zod by seamlessly accessing both parameters and queries

In the zod-middleware documentation, an example is provided: export async function endpointCode(req: TypedRequestBody<typeof bodySchema>, res: Response) { const typedBody = req.body; return res.json(typedBody); } This example demonstrates access ...

Following the npm update, encountering errors with webpack

Upgrading the npm package to version 8.2.0 has caused issues in my React application. Here is a screenshot of the problem: https://i.stack.imgur.com/noQIz.png These are the error messages I see in the console: [HMR] Waiting for update signal from WDS.. ...

The click event triggered by the onclick clone/function may not always activate the click handler

As a newcomer in the JavaScript domain, I am encountering an issue where the first clone created after clicking 'add more' does not trigger my click me function. However, every subsequent clone works perfectly fine with it. What could be causing ...

There seems to be an issue with gulp as it is not functioning properly and the version information is

Currently, I am working on a project and have made the decision to utilize gulp for watching and transpiling Typescript files. Below are the steps I followed to set everything up: All of these actions were performed within the main directory of my projec ...

Error: No provider found for _HttpClient in the NullInjector context

Hello everyone, I am new to Angular and currently facing an issue that has me stuck. The error message I'm receiving is as follows: ERROR NullInjectorError: R3InjectorError(Standalone[_AppComponent])[_ApiCallServiceService -> _ApiCallServiceService ...

What is the method for implementing an Inset FAB with Material UI in a React project?

Currently, I am working on a project that requires an "Inset Fab" button to be placed between containers. After referencing the Material Design documentation, I discovered that the component is officially named "Inset FAB". While I was able to find some tu ...

Exploring the filter method in arrays to selectively print specific values of an object

const array = [ { value: "Value one", label: "Value at one" }, { value: "Value 2", label: "Value at 2" }, { value: "" , label: "Value at 3" } ...

The interface 'IProduct' does not include several properties found in type 'IProduct[]', such as length, pop, push, concat, and many more

My goal is to transfer data between parent and child components using React and TypeScript. I have defined the following interfaces: export interface IProduct { id: string; name: string; price: string; image: string; ...

What is the best way to export a default object containing imported types in TypeScript?

I am currently working on creating ambient type definitions for a JavaScript utility package (similar to Lodash). I want users to be able to import modules in the following ways: // For TypeScript or Babel import myutils from 'myutils' // myuti ...

Typescript error in RxJS: Incorrect argument type used

I came across this code snippet from an example in rxjs: Observable.fromEvent(this.getNativeElement(this.right), 'click') .map(event => 10) .startWith({x: 400, y: 400}) .scan((acc, curr) => Object.assign({}, acc, {x: acc ...

Saving any type of file in SQL Server with a field type of varbinary(max) can be achieved by utilizing Angular with ASP.NET Core to create a REST API

I am currently facing an issue while attempting to save a file, such as an image, in the Microsoft SQL Server Management Studio through asp .NET core for the Rest API. I have managed to create a base64 representation of the file, but I am unsure about the ...

Utilizing TypeScript generic types as a key for an object

function createRecord<T extends string>(key: T): Record<T, string> { return { [key]: 'asdf' }; } Encountering an issue: The type '{ [x: string]: string; }' is not matching with the expected 'Record<T, st ...

Troubleshooting React child problems in TypeScript

I am facing a coding issue and have provided all the necessary code for reference. Despite trying numerous solutions, I am still unable to resolve it. export class JobBuilderOptimise extends React.Component<JobBuilderOptimiseProps & JobBuilderOptim ...

Locate the minimum and maximum values between two inputted dates

I'm looking for a solution that provides strongly typed code. The problem arises when trying to implement solutions from a related question - Min/Max of dates in an array? - as it results in an error. TS2345: Argument of type 'Date' is not ...

Adjust the column count in mat-grid-list upon the initial loading of the component

My goal is to implement a mat-grid-list of images with a dynamic number of columns based on the screen size. Everything works perfectly except for one small glitch – when the grid first loads, it defaults to 3 columns regardless of the screen size until ...

Ways to resolve the error message "TypeError: 'setOption' is not a function on type 'MutableRefObject' in React"

CODE export default function EChart({ option, config, resize }) { let chart = useRef(null) let [chartEl, setChartEl] = useState(chart) useEffect(() => { if (resize) { chartEl.resize() } if (!chartEl.cu ...

Is there a method to run code in the parent class right after the child constructor is called in two ES6 Parent-Child classes?

For instance: class Parent { constructor() {} } class Child { constructor() { super(); someChildCode(); } } I need to run some additional code after the execution of someChildCode(). Although I could insert it directly there, the requirement is not to ...

Using TypeScript to define data types for Supabase payloads

Currently, I'm working on integrating supabase into my ReactJS Typescript project. However, I'm unsure about the data type of the channel payload response and I aim to extract the eventType along with the new data. const handleInserts = () => ...

Using Angular Form Builder to assign a value depending on the selected option in a dropdown menu

My approach to Angular Form Builder initialization includes a group that looks like this: contactReason: this.formBuilder.group({ description: '', source: this.sourceType() }) For the 'description' field, I hav ...

Error: Unable to Locate Module (Typescript with baseUrl Configuration)

Struggling to implement custom paths in my TypeScript project, I keep encountering the "webpackMissingModule" error due to webpack not recognizing my modules. I've attempted various solutions without any success. Any suggestions or ideas? Some packa ...