What is the best way to declare a class as global in TypeScript without repeating code?

Is it possible to define a global class in TypeScript without repeating code?

The following approach doesn't seem to work:

declare global {
  class A {
    hi() { return "hi" }
  }
}

export {}

As a result, I had to resort to repeated code usage. You can test this here.

declare global {
  class A {
    hi(): string
  }
}

(window as any).A = class A { 
  hi() { return "hi" }
}

export {}

Answer №1

Sorry, I can't seem to find a perfect solution for this issue. Without something similar to microsoft/TypeScript#39504, some level of duplication may be inevitable.

One potential approach is outlined below, with a set amount of extra work involved. This could be beneficial if your class definition contains more than just a couple of methods or properties:

const _A = class A {
  hi() { return "hi" }
}

declare global {
  var A: typeof _A
  interface A extends InstanceType<typeof A> { }
}
window.A = _A; // or globalThis.A = _A;

export { }

Initially, you define your class as A and assign it to another variable called _A. By utilizing typeof _A, you reference the type of the class constructor and incorporate it into your global scope. Class declarations introduce both a named value for the constructor and a named type for the instance, so augmenting the global scope with a class expression and typeof necessitates manual handling. This explains why the constructor uses var and the instance type requires an interface.

(If TypeScript were to include a typeof class feature as discussed in microsoft/TypeScript#41581, this process might become smoother, but until then, this is the most effective method).

It's important to note that the interface A type employs the InstanceType<T> utility type; while generally reliable, there are certain edge cases such as generic classes that may warrant further testing in your specific scenarios.

Once the global scope recognizes the global A class, assigning the _A constructor to it becomes seamless.

Playground link to code

Answer №2

To assign a new property (let's call it A class) to the global object window, use the following code:

declare global {
  class A {
    hi(): string
  }

  interface Window { AClass: A; }
}

window.AClass = window.AClass || {};

window.AClass.hi();

PlaygroundLink

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

Issue encountered with JavaScript function within TypeScript file connected to HTML code

I am currently working on a simple SharePoint web part and encountering an issue with using a function from another module file in my main file. Snippet from the JSFunctions.module.js file (where I define my function): function getApi(){ [my code]... }; ...

The Angular Observable continues to show an array instead of a single string value

The project I am working on is a bit disorganized, so I will try to explain it as simply as possible. For context, the technologies being used include Angular, Spring, and Maven. However, I believe the only relevant part is Angular. My goal is to make a c ...

Steps for updating a server component after redirectionWould you like to know how

One of my server components fetches and displays data only when the user is authorized: function CheckAuthorization() { const isAuthenticated = // check if user is authorized return ( <div> {isAuthenticated ? ( <DisplayAutho ...

Combining portions of objects in Angular2

I want to combine two identical type observables in Angular2 and return an observable of the same type in a function. My goal is to: transform this setup: obs1.subscribe(obs => console.log(obs)) (where I receive): { count: 10, array: <some ...

Error: An unexpected identifier was found within the public players code, causing a SyntaxError

As a newcomer to jasmine and test cases, I am endeavoring to create test cases for my JavaScript code in fiddle. However, I'm encountering an error: Uncaught SyntaxError: Unexpected identifier Could you guide me on how to rectify this issue? Below is ...

Using ESLint to enforce snake_case naming conventions within TypeScript Type properties

When working with TypeScript, I prefer to use snake_case for properties within my Interfaces or Types. To enforce this rule, I have configured the ESLint rule camelcase as follows: 'camelcase': ["error", {properties: "never"}], Even though the E ...

Error: The nested property of the dynamic type cannot be indexed

Within my coding project, I've devised an interface that includes various dynamic keys for API routes, along with the corresponding method and response structure. interface ApiRoutes { "auth/login": { POST: { response: { ...

Angular 8: How to Filter an Array of Objects Using Multiple Conditions

I am faced with the following scenario where I need to filter an array of objects based on lineId, subFamily, and status. My current code successfully filters based on lineId, but now I also need to include a condition for subFamilyId. I have two specifi ...

What steps should I take to resolve a 'Missing environment variable' issue in the Sanity platform?

No matter what I've tried, I can't seem to fix the error that keeps occurring. An uncaught error is popping up, saying that the environment variable NEXT_PUBLIC_SANITY_DATASET is missing. http://localhost:3333/static/sanity-5377bc10.js:4605 ...

React TypeScript - Module not found

Organizational structure: src - components - About.tsx In an attempt to optimize performance, I am experimenting with lazy loading: const About = React.lazy(() => import('components/About')); However, Visual Studio Code is flagging &ap ...

The test.ts file does not contain any type definitions

While I am able to successfully utilize my types in .ts files, I am facing difficulties in understanding why it's failing in .test.ts files, even though both files are located in the same folder. Check out the code in the .ts file below: https://i.s ...

Displaying object properties in React and rendering them on the user interface

Within my React application, I am retrieving data from an API using the following code snippet: function PlayerPage() { interface PlayerDataType { id: number; handle: string; role: string; avatar: string; specialAbilities: null; s ...

How can I create an input field in MUI that restricts input to letters, numbers, and dashes

Is there a way to configure an MUI input field so that it only accepts letters, numbers, and dashes while excluding spaces and symbols such as (*&^%$#@!,.<>{}[])? Specifically, I want to allow characters that wouldn't disrupt a URL, like . Tha ...

Compiled TypeScript files are missing require statements for imported components

Recently delved into Angular 2 and encountered an unusual issue. I kicked off using the Angular 2 Quickstart repository on GitHub and incorporated some components with templates. For example: import { Component } from '@angular/core'; import { ...

What is the best way to leverage the Nextjs Link tag while also incorporating the data-dismiss attribute?

Currently, I am working on a Next.js project. In the mobile view, my navigation menu utilizes a modal to toggle the navbar. However, I have encountered an issue where when I click on a navigation link, the data gets dismissed but the link itself does not n ...

Access the elements within arrays without using the square brackets

I am trying to access data from a list, but I am having trouble using square brackets []. The getTalonPaie function calls the get method from the HttpClient service and returns an observable with multiple values. However, when I try to store these values i ...

Declaratively assign ambient typings to an unfamiliar object in Typescript

I am facing an issue with an external library named "gapi" that is set to a property on the window object as window.gapi. I would like to keep it there while using the @types/gapi declaration. Is there a way to achieve this, like the following code snippet ...

Encountering an error of TypeError while attempting to generate a new GraphQL

Currently using Apollo-Server/TypeScript with graphql-tool's makeExecutableSchema() to set up schema/directives. Encountering an error while attempting to add a basic GraphQL Directive: TypeError: Class constructor SchemaDirectiveVisitor cannot be in ...

Leveraging RXJS for real-time response to keyboard and mouse click combinations in web

I am new to RXJS and looking for a way to drag an HtmlElement when the user presses the space key and then drags the element with the mouse. The dragging should be initiated by either pressing the SPACE key followed by a left click, or vice versa. The dra ...

Retrieve the input type corresponding to the name and return it as a string using string template literals

type ExtractKeyType<T extends string, K extends number> = `${T}.${K}`; type PathImpl<T, Key extends keyof T> = Key extends string ? T[Key] extends readonly unknown[] ? ExtractKeyType<Key, 0 | 1> : T[Key] extends Record<str ...