Automatically deducing types or implementing intricate type validation based on an array

I am struggling with implementing type checking in the register function. Currently, it accepts an array of Module[], which allows any options for a module. I want to set restrictions without using type assertion. Any advice on how to accomplish this would be greatly appreciated.

register([
    {
        use: NumberModule,
        options: {
            // I expected type checking to work without assertion
            numb: 1
        } as NumberModuleOptions // I want to eliminate this assertion
    },
    {
        use: StringModule,
        options: {
            // I expected type checking to work without assertion
            str: 'hello'
        } as StringModuleOptions // I want to remove this
    }
])

Full code

interface Module<Options, Contructor = ModuleContructor<Options> {
    use: Contructor
    options: Options
}


type ModuleContructor<Type> = new (...args: any[]) => ModuleInterface<Type>


interface ModuleInterface<Type> {
    handle(data: Type): void
}



interface NumberModuleOptions {
    numb: number
}

class NumberModule implements ModuleInterface<NumberModuleOptions> {
    handle(data: NumberModuleOptions): void {
        console.log(data)
    }

}

interface StringModuleOptions {
    str: string
}

class StringModule implements ModuleInterface<StringModuleOptions> {
    handle(data: StringModuleOptions): void {
        console.log(data)
    }

}



function register(modules: Module<unknown>[]): void {
 // some implementation
}

Answer №1

Using Module<unknown>[] will result in register() accepting more than necessary for modules, as unknown can accept anything. The ideal scenario is to accept a tuple type like

[Module<X>, Module<Y>, Module<Z>]
, where X, Y, and Z are inferred. To achieve this, make register() generic with the type T corresponding to [X, Y, Z] and have modules as a mapped tuple type, wrapping each element of T with Module<T>. The concept looks like this:

function register<T extends any[]>(
  modules: [...{ [I in keyof T]: Module<T[I]>}]): void {
  // implementation
}

This is a variadic tuple type indicating that a tuple inference is preferred over an array.

However, this setup is still too lenient; Module<X>, essentially

Module<X, ModuleContructor<X>>
, relies on X in both the use and options properties. To infer X from use and only check options against it, an inference break on options is required. We need the first X in
Module<X, ModuleContructor<X>>
to be a non-inferential type parameter usage, as suggested in microsoft/TypeScript#14829. Introduce NoInfer<X> to block inference:

type NoInfer<T> = T extends infer U ? U : never

With this, the updated register() function becomes:

function register<T extends any[]>(modules: [...{ [I in keyof T]:
  Module<NoInfer<T[I]>, ModuleContructor<T[I]>> }]): void {
  // implementation
}
...

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 Typescript object may be null even with its initial value set

1: let a: Record<string, any> | null = {}; 2: a['b'] = 2; Encountered the TS2531: Object is possibly 'null' error on Row 2 despite having an initial value. To address this issue, the code was updated as follows: 1: let a: Record ...

Having trouble accessing the property 'prototype' of null in Bing Maps when using Angular4

I'm currently working on creating a Bing component in Angular 4, but I'm facing issues with rendering the map. Below is my index.html file: <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title> ...

Does the class effectively implement the interface even if the method of a member variable has undefined arguments?

Let's take a closer look at my code, which lacks proper descriptions. Here is the interface: interface IModel<T = any> { effects: { [key: string]: (getState: () => T) => void; }; } interface IState { name: string; age: numbe ...

Returning a 'never' type from a function in React using Typescript

Basically, I have a function that initiates the OAuth flow (redirecting to Google OAuth login page, for example): async function signIn() { // start OAuth flow } And let's say I want to use it in a useEffect hook like this: ... useEffect(() => { ...

Try out NextJS API middleware by running tests with Jest

I have a middleware setup in my NextJS API route, located at /src/middleware/validateData/index.ts. It's used to validate request data using a schema. import { NextApiRequest, NextApiResponse } from 'next'; import schema from './schema ...

Is it possible to implement drag and drop functionality for uploading .ply, .stl, and .obj files in an angular application?

One problem I'm facing is uploading 3D models in angular, specifically files with the extensions .ply, .stl, and .obj. The ng2-upload plugin I'm currently using for drag'n'drop doesn't support these file types. When I upload a file ...

Observable task queuing

Here's the scenario: In my application, the user can tap a button to trigger a task that takes 2 seconds to complete. I want to set up a queue to run these tasks one after another, in sequence. I am working with Ionic 3 and TypeScript. What would be ...

Tips on selecting an element with matching element attributes on a button that contains a span tag using Protractor in TypeScript

https://i.sstatic.net/LAhi8.jpg Seeking assistance with creating a protractor TypeScript code to click a button with _ngcontent and span class. Does anyone have any suggestions on how to achieve this? Here is the code snippet from the site: <form _ngc ...

How can I resolve the infinite loop issue caused by Angular Auth guard when using routing?

My current struggle lies within the authentication guard logic and routing setup. In my app-routing.module.ts file, I have defined 3 routes: const routes: Routes = [ { path: '', loadChildren: () => import('./browse/browse.mod ...

The concept of a generic type serving as a characteristic of an incoming argument

What is the best way to assign a type property of an argument to a generic in TypeScript? Here's the code snippet: const foo = <T = someObject.bar>(someObject: {[string]: any}): T => { return someObject.bar } How can we set the type of ...

What is the best way to execute a GraphQL mutation query with a variable object?

My Register Mutation GraphQL Query is causing an error when executed. The error message states: "Variable "$options" of type "UsernamePasswordInput" used in position expecting type "UsernamePasswordInput!". How can I properly run my GraphQL query for mutat ...

typescript locate within the union type in the mapping expression

Consider the following: type X = { label: 'Xlabel', X_id: 12 }; type Y = { label: 'Ylabel', Y_id: 24 }; type Z = { label: 'Zlabel', Z_id: 36 }; type CharSet = X | Y | Z; I am looking for type CharSetByLabel = Map<CharSet& ...

Protected class, yet not transferable

My output varies based on the type of input provided. I have a custom guard in place to protect the input, but I'm still having trouble assigning it to the declared output: type InputType<Sub extends SubType> = { a: Sub, b: string } type SubTyp ...

Transforming functions into a new typed object with different function signatures

I am currently updating some React/Redux code that previously followed an older pattern to a more modern "hooks" based approach, using TypeScript. In the old pattern, we utilized "class-based" components and passed their "dispatch" functions using mapDisp ...

Tips for maintaining a healthy balance of tasks in libuv during IO operations

Utilizing Typescript and libuv for IO operations is crucial. In my current situation, I am generating a fingerprint hash of a particular file. Let's say the input file size is approximately 1TB. To obtain the file's fingerprint, one method involv ...

Why does my array seem to update only once in the view?

I am currently working on a project that aims to visually represent sorting algorithms, but I have encountered an issue. In order to effectively visualize the sorting process of an algorithm, it is crucial to display every change in the array as the proc ...

Angular 5 encountering issue with @Injectable annotation causing TypeScript error

While trying to compile my code, I encountered the following error: import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable() export class TaskService { constructor(private http: Ht ...

JavaScript - Trouble encountered while trying to use splice to insert one array into another array

I've been working on creating a Cache Hashtable using JavaScript. When I use the code cache.splice(0,0, ...dataPage);, it inserts my data starting from the first position up to the length of dataPage. Assuming that my dataPage size is always 10. Th ...

Migration of old AngularJS to TypeScript in require.js does not recognize import statements

I am looking to transition my aging AngularJS application from JavaScript to TypeScript. To load the necessary components, I am currently utilizing require.js. In order to maintain compatibility with scripts that do not use require.js, I have opted for usi ...

Issues with Angular 2 and Deserialization of .NET List<T>

I'm encountering issues when trying to deserialize a .NET List into an Angular 2 array. An error keeps popping up: ERROR Error: Cannot find a differ supporting object...NgFor only supports binding to Iterables such as Arrays. I've looked around ...