Is using global variables as a namespace a good practice? Creating ambient TypeScript definitions in StarUML

I'm currently working on creating TypeScript type definitions for the StarUML tool. While I've been successful in defining most of the API, I've hit a roadblock when it comes to linking a JavaScript global variable ("type" in this case) with a TypeScript namespace that contains classes.

(A) The Issue at Hand

Within StarUML, there exists a global variable called type which registers numerous classes from unknown sources. For example, both type.Element and type.Model are classes (not elements). These two types are commonly used in JavaScript statements like if (x instanceof type.Element).

  • In JavaScript, these classes are typically utilized in statements like if (x instanceof type.Element).
  • In TypeScript, my goal is to define signatures such as f(e : type.Element) and enable intelli-sense features for expressions like myElement._id (where _id is an attribute of the class Element).

(B) Initial Attempt: Treating "type" as a Variable

Initially, I attempted to treat the type as a variable:

// type.d.ts

declare class Element {
    _id: string
    // ...
}
declare class Model extends Element {
    name: string
    // ...
}

declare const type = {
    "Element" = Element,
    "Model" = Model
    // ...
}

However, this approach led to the following error:

S1254: A 'const' initializer in an ambient context must be a string or numeric literal or literal enum reference

Despite its limitations, this solution highlighted the essence of type: a registry linking class names to their respective classes.

(C) Revised Approach: Defining "type" as a Namespace

After poring over the TypeScript documentation and multiple attempts, I formulated a TypeScript file named types.d.ts, where I structured the code as follows:

// types.ts
export namespace type {
    class Element {
        _id: string
        // ...
    }
    class Model extends Element {
        name: string
    }
    // ...
}

(D) Usage in Client Code

Below is an illustrative code snippet (main.ts) employing this API definition. Both type.d.ts and main.ts reside at the top level for simplicity.

// (1)     /// <reference path="./types.d.ts" />
// (2)     import {type} from "./types"
// (3)     declare var type

function hello(m: type.Element): void {
    console.log("    hello: (" + e._id + ')')
}
console.log(type)
console.log(type.Element)

Despite several permutations of uncommenting lines, I'm yet to achieve all desired functionalities simultaneously.

(D.2) Expected vs. Actual Results

  • (a) Properly defined types within the function hello should exhibit proper TypeScript behavior.
  • (b) Intelli-sense capabilities should function seamlessly for expressions like e._id.
  • (c) The last line ought to accurately display the type.Element class.

Frustratingly, achieving these goals concurrently has proven elusive, despite various importing strategies.

(D.3) Current Challenges

  • (1) Implementing line (1) /// <reference ... has proved particularly challenging, even after exploring solutions like leveraging tsconfig settings.

  • (2) Although import {type} ... appears promising for namespaces, console.log(type.element) returns undefined at runtime.

  • (3) Declaring var type leads to functional JavaScript code but complicates matters further due to conflicts.

Simultaneous presence of (2) and (3) triggers TypeScript errors owing to conflicts arising from the dual nature of type as both a namespace and a variable.

(D.4) Seeking Resolutions

Despite extensive research into TypeScript resources and related blogs, clarity eludes me. Uncertainty looms over whether the issue lies in my implementation approach (as in section C) by treating the variable type as a namespace, or if challenges arise during compilation/runtime while invoking this namespace/variable.

Answer №1

Disclaimer: I consider myself proficient in TypeScript, though not so much when it comes to handling .d.ts files. However, after testing this locally, it appears to align with the information provided in the official documentation, especially this specific example.

A .d.ts file serves as a repository for ambient declarations; there is no need to utilize export within it (as far as my knowledge extends). The primary function of this file is to declare entities that are already in existence (such as the type global and its attributes generated by the SmartUML library at runtime, in this scenario).

In your .d.ts file, you essentially define a namespace encapsulating these classes:

/**
 * Global namespace for the SmartUML library.
 */
declare namespace type {
    /**
     * Definition of the 'Element' class in SmartUML.
     */
    class Element {
        /**
         * Unique identifier for the element.
         */
        _id: string;
        // ...
    }
    /**
     * Description of the 'Model' class in SmartUML.
     */
    class Model extends Element {
        /**
         * The name assigned to the model.
         */
        name: string;
        // ...
    }
    // ...
}

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

What is the best way to declare a collection of objects in TypeScript?

Need assistance with TypeScript - Can anyone help? I'm having trouble deciphering the error message in relation to the code snippet below. My goal is to create an array of objects, but it doesn't seem to be working as expected. interface FieldC ...

An error is anticipated when () is added, but surprisingly, I still encounter an error as well. This issue arises in React-Native and Typescript

I am still relatively new to React-Native, but I have been using React-Native, TypeScript, and integrating it with Firebase. An unusual error has occurred, which is visible in the screenshot below. However, when checking in VSC, the error seems to be non-e ...

I'm trying to figure out how to incorporate types for utilizing Intl.ListFormat in node v12. Can

I am currently working with nodeJS version 12.10.0, which now includes support for Intl.ListFormat. I am also using Typescript version 3.6.3. However, when compiling my code with Typescript, I encounter the following error: Property 'ListFormat' ...

Why am I unable to retrieve the property from the JSON file?

Below is the provided JSON data: data = { "company_name": "חברה לדוגמה", "audit_period_begin": "01/01/2021", "audit_period_end": "31/12/2021", "reports": [ ...

Avoid circular dependencies in Angular 6 to ensure proper association between modules

When working with TypeScript, how should I handle the scenario where Cat has an owner: Person Person owns a pet: Cat Cat import {Person} from './person' export class Cat { owner: Person constructor(){ this.owner = new Pers ...

The error code TS2345 indicates that the argument '{ read: typeof ElementRef; }' cannot be assigned to the parameter '{ read?: any; static: boolean; }'

Currently in the process of updating my Angular application from version 7 to version 8. Upon running ng serve, I encounter the following error: Error TS2739: Type '{}' is missing the following properties from type 'EmployeeModel': stat ...

delayed updating of property not visible in angular 10 immediately

I needed to hide a div based on a condition, so I decided to use the hidden property like below: <div [hidden]="isControlDisplayed()?false:true"> The isControlDisplayed() method determines whether to show or hide the div based on the value ...

Using the TypeScript NextPage function along with the getInitialProps static method and @typescript-eslint/unbound-method

After enabling typescript-eslint with its recommended settings, I encountered an issue in my code. I came across this helpful post on Stack Overflow: Using getInitialProps in Next.js with TypeScript const X: NextPage = props => {/*...*/} X.getInitialP ...

When integrating the @azure/msal-angular import into the Angular application, the screen unexpectedly goes blank,

Starting a new Angular app and everything is rendering as expected at localhost:4200 until the following change is made: @NgModule({ declarations: [ AppComponent, HeaderBannerComponent, MainContentComponent, FooterContentinfoComponent ...

Angular version 6 and its routing functionality

Hey there, I need some help with setting up routers in my Angular app. Here is the code from my files: import {NgModule} from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const APP_ROUTES: Routes = [ {pa ...

Encountering an Invalid JSON error on the Developer console

I'm in the process of building a React application and aiming to establish a connection with my Back4App database. Within the Back4App dashboard, there exists a Person class containing data that needs to be retrieved. It appears that the call is being ...

reconfigure components by resetting settings on a different component

In the interface, I have a section that displays text along with a unique component titled FilterCriteriaList. This component includes custom buttons that alter their color when clicked. My goal is to reset the settings in the FilterCriteriaList component ...

Angular 6 Calendar Template issues with parsing: Unable to link to 'view' as it is not recognized as a valid property of 'div'

I am in the process of developing an application that utilizes this angular calendar. My tech stack includes Angular 6 with AngularFire2 and Firebase. Below is my app.module.ts file: import { BrowserModule } from '@angular/platform-browser'; imp ...

Angular Appreciation Meter

Looking to create a rating system using Angular. The square should turn green if there are more likes than dislikes, and red vice versa (check out the stackblitz link for reference). Check it out here: View demo I've tried debugging my code with con ...

A guide to accessing parent attributes in Vue3 using typescript

Within my child component, I am facing an issue where I need to access the parent object but the commented lines are not functioning as expected. The structure of AccordionState is defined below: export type AccordionKeys = | "open" | "disa ...

One typical approach in React/JavaScript for monitoring the runtime of every function within a program

Experimenting with different techniques such as performance.now() or new Date().getTime() has been done in order to monitor the processing time of every function/method. However, specifying these methods within each function for time calculation purposes h ...

Playing around with TypeScript + lambda expressions + lambda tiers (AWS)

Having trouble importing modules for jest tests in a setup involving lambdas, lambda layers, and tests. Here is the file structure: backend/ ├─ jest.config.js ├─ package.json ├─ babel.config.js ├─ layers/ │ ├─ tsconfig.json │ ├ ...

What is the official name of the key type for the Built-in Object?

There was a built-in type that I used in the past which represented the union of all possible object keys. It was named objectKey or something similar. Here is an example: type objectKey = string | number | symbol Unfortunately, I am drawing a blank on t ...

Updating the state in React Native does not occur

I'm facing an issue where I can't seem to update the state using useState while coding in React Native. The component in question is a styled TextInput named SearchField. Can anyone help me figure out what I might be doing wrong that's preve ...

Ensuring Type Compatibility Between Classes and Object Literals in TypeScript

When working with TypeScript, it is important to note that an object literal can be assigned to a class typed variable as long as the object provides all properties and methods required by the class. class MyClass { a: number; b: string; } // The co ...