Typescript patterns for creating a modular library design

Transitioning a JavaScript project to TypeScript has been challenging for me, especially when it comes to establishing a solid design pattern for the library's modularity.

Main Concept

The core functionality of my library is minimal. For instance, it may provide browser specifications as an object:

{
    browser:"firefox",
    version:"10.1.5",
    platform:"linux",
    screen-width:"1920",
    // .. etc
}

This library will be installed through NPM. However, to fully utilize its capabilities, users must install "modules" that process the above-mentioned object in unique ways.

For example, one module might identify which CSS features are unsupported in a particular browser version:

{
    unsupportedFeatures:[
        "x",
        "y",
        "z",
        // ... etc
    ]
}

Another module could take both the core library result and the previous module’s outcome to analyze the DOM for any unsupported CSS properties defined.

{
    notSupported:[
        "x",
        "y",
        // ... etc
    ]
}

Note: The mentioned functionalities are hypothetical examples illustrating how modules depend on the core library results as well as each other.


My Attempts So Far

I experimented with defining the core library as a function and adding modules as prototypes.

An issue I encountered was the lack of type definitions for both the core library and the added prototype functions.

I also explored defining the core library as a class, but this approach also led to compiler errors.

Lastly, merging namespace interface declarations yielded additional compilation issues.

Despite trying different solutions, none seemed to effectively work within the realm of TypeScript.

How can I tackle this challenge in TypeScript? What would be the ideal design pattern to follow for creating modular and extensible libraries while ensuring type safety and auto-completion?

Answer №1

Here is the modified playground code that reflects my personal touch:

// Central Library ---------------
namespace coreLib { 
    export interface customInterface { 
        browser: string,
        version: string
    }

    const modules: ((customInterface) => coreLib.customInterface)[] = [];
    export function attachModule(module: (customInterface) => coreLib.customInterface) { 
        modules.push(module);
    }

    export function CoreLibrary (): customInterface { 
        let result: customInterface = {
            browser: "",
            version: ""
        }
        // performing operations
        result.browser = "firefox";
        result.version = "1.0.0";
        modules.forEach((module) => { 
            result = module(result);
        })
        return result;
    }
}

// Extension Module ---------------
namespace coreLib {
    export interface customInterface {
        something?: boolean;
    }
    export function myExtension (input:coreLib.customInterface): coreLib.customInterface { 
        // additional functionality
        input.something = true;
        return input;
    } 
}

// End User Section ---------------
coreLib.attachModule(coreLib.myExtension);
const output = coreLib.CoreLibrary();
console.log(output.browser);
console.log(output.something);

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

The map function is calling an unresolved function or method named "map"

I'm encountering an error with the map method in my code, even after correctly importing 'rxjs/add/operator/map'. I've followed all the necessary steps and upgraded to rxjs 5.0.1, but the error persists. Do you have any suggestions on h ...

WebStorm provides alerts for objects, types, and directives within Angular, yet they function properly

Why is WebStorm displaying warnings for objects, types, and directives in Angular Template HTML even though they are functioning correctly? Despite the fact that all types and Angular directives in the HTML structure are working fine within Angular on Web ...

Mastering the art of constraining TypeScript function parameters using interface properties

Hey there, I've been exploring ways to restrict a function parameter so that it only accepts "strings" related to interface properties, similar to what I achieved in the validate fields function: Please note: The TypeScript code provided here is simp ...

Bringing in personalized data types using unique import aliases

Recently, I made changes to my Next.js project by upgrading it to TypeScript. One of the modifications I made was updating my import alias from @/* to @*. Below is the new configuration in my tsconfig.json. { "compilerOptions": { "targ ...

Angular is used to call a function that captures a specific div and then waits for the capture to be completed before

I'm facing a challenge where I need to handle the capturing of a div using a method called capture() within another method. Take a look at the code snippet below: theimage; // declaring the variable callcapture() { // perform certain actions t ...

Function modifies global variable

What could be causing the global variable to change when using the function write_ACK_ONLY()? I'm passing the array rxUartBuffer to write_ACK_ONLY() as data = new Array(20), but upon checking the Log Output, it seems that the function is also modifyin ...

Troubleshooting problem with refreshing URL on "ionic serve" mode

After transitioning my project from Ionic 2 to Ionic 3, I've encountered an issue with ionic serve and the rebuilding process. Initially, when I build the project, everything functions as expected. However, I've noticed that the URL in the brows ...

Leveraging Class Types with Generics

Take a look at this example: https://www.typescriptlang.org/docs/handbook/2/generics.html#using-class-types-in-generics To make it work, I just need to call a static method before instantiation. Let's adjust the example like this: class BeeKeeper { ...

Implementing Asynchronous context tracking within a Remix application utilizing Express as the server

Utilizing Remix with Express as the server, I aim to develop an Express middleware that establishes an async context to grant all downstream functions (especially those in the "backend" Remix code) access to this context within the scope of a single reques ...

Encountering an Issue with Dynamic Imports in Cypress Tests Using Typescript: Error Loading Chunk 1

I've been experimenting with dynamic imports in my Cypress tests, for example using inputModule = await import('../../__tests__/testCases/baseInput'); However, I encountered an issue with the following error message: ChunkLoadError: Loading ...

Encountering an ECONNREFUSED error upon upgrading from Next.js 12 to 13

After upgrading from Nextjs 12 to 13, I am experiencing issues where every time I try to run the application, I encounter ECONNREFUSED to my local host but the port seems to keep changing. This results in the application not rendering properly. > <a ...

Contact the help desk and receive information that is currently unknown

There are a few issues that I'm struggling to resolve. I am utilizing SwaggerService to fetch data, but the response is coming back as undefined. import {SwaggerService} from '../../services/swagger.service'; export class TestComponent im ...

Using useState, react, and typescript, is there a way to set only the icon that has been clicked to

When I click on the FavoriteIcon inside the ExamplesCard, all the icons turn red instead of just the one that was clicked. My approach involves using useState to toggle the icon state value between true and false, as well as manipulating the style to adjus ...

The input type '{}' does not match the expected type 'Readonly<IIdeasContainerProps>'. The property '...' is not found in the type '{}'

Having recently started using TypeScript, I'm encountering some issues when attempting to execute this code snippet. Error The error message reads as follows: Failed to compile 13,8): Type '{}' is not assignable to type 'Readonly &l ...

Error in Typescript TS2322: Observable Type 'boolean | {}' - Using Angular 5 and Typescript 2.4.2

After upgrading from version 4 to 5, I'm puzzled by the plethora of TypeScript TS2322 errors I'm encountering. The migration involved setting up a new Angular project with the Angular CLI. Angular CLI: 1.5.5 Node: 8.9.1 OS: darwin x64 Angular: 5 ...

'The signatures of each of these values are not compatible with one another.' This error occurs when using find() on a value that has two different array types

Here's the code snippet I'm attempting to run within a TypeScript editor: type ABC = { title: string } type DEF = { name: string } type XYZ = { desc: ABC[] | DEF[] } const container: XYZ = { desc: [{title: & ...

Issue with TypeORM findOne method causing unexpected output

I am encountering an issue with my User Entity's Email Column when using TypeORM's findOne function. Instead of returning null for a non-existent email, it is returning the first entry in the User Entity. This behavior does not align with the doc ...

Join our mailing list for exclusive updates on Angular 6

ingredients : Array additionalIngredients : Array In my code, I have two different methods for subscribing: this.ingredients.valueChanges.subscribe(val=> { console.log(val); } this.additionalIngredients.valueChanges.subscribe(val2=> { console.lo ...

How can I assign a type to an array object by utilizing both the 'Pick' and '&' keywords simultaneously in TypeScript?

As a beginner in TypeScript, I am looking to declare a type for an array object similar to the example below. const temp = [{ id: 0, // number follower_id: 0, // number followee_id: 0, // number created_at: '', // string delete_at: &ap ...

Google Maps on Angular fails to load

I'm currently working on integrating AGM into my Ionic 2 project. app.module.ts ... import { AgmCoreModule } from '@agm/core'; import { DirectionsMapDirective } from '../components/directions-map'; @NgModule({ declarations: [ ...