TypeScript overlooking mismatched type arguments in generics

Currently, I am in the process of constructing a pluggable interface/class system that enables an "output" to connect with an "input". To my surprise, TypeScript seems to overlook any warnings or errors that might arise when a compatible interface is paired with an incompatible generic. I am unsure if I am approaching this the wrong way, if there are additional steps I can take to enforce proper checking, or if this functionality is simply not supported in TypeScript 2.9.2.

interface IValueA {
  fooA(): void;
}

interface IValueB {
  barB(): void;
}

interface ISomethingA<T> {
  goToB(thing: ISomethingB<T>): void;
}

interface ISomethingB<T> {
  goToA(thing: ISomethingA<T>): void;
}

interface ISomethingAS extends ISomethingA<string> {}
interface ISomethingAN extends ISomethingA<number> {}

interface ISomethingBS extends ISomethingB<string> {}
interface ISomethingBN extends ISomethingB<number> {}

export class SomethingA<T> implements ISomethingA<T> {
  public goToB(thing: ISomethingB<T>): void {
    console.log("SomethingA", "goToB", thing);
  }
}

export class SomethingAN implements ISomethingAN {
  public goToB(thing: ISomethingBN): void {
    console.log("SomethingA", "goToB", thing);
  }
}

export class SomethingAS implements ISomethingAS {
  public goToB(thing: ISomethingBS): void {
    console.log("SomethingA", "goToB", thing);
  }
}

export class SomethingB<T> implements ISomethingB<T> {
  public goToA(thing: ISomethingA<T>): void {
    console.log("SomethingA", "goToA", thing);
  }
}

export class SomethingBN implements ISomethingBN {
  public goToA(thing: ISomethingAN): void {
    console.log("SomethingA", "goToA", thing);
  }
}

export class SomethingBS implements ISomethingBS {
  public goToA(thing: ISomethingAS): void {
    console.log("SomethingA", "goToA", thing);
  }
}

const a = new SomethingA<IValueA>();
const b = new SomethingB<IValueB>();

const as = new SomethingAS();
const an = new SomethingAN();

const bs = new SomethingBS();
const bn = new SomethingBN();

a.goToB(b); // ISomethingA<IValueA> expects ISomethingB<IValueA> but accepts ISomethingB<IValueB>

as.goToB(bn); // ISomethingAS (ISomethingA<string>) expects ISomethingBS (ISomethingB<string>) but accepts ISomethingBN (ISomethingB<number>)
an.goToB(bs); // ISomethingAN (ISomethingA<number>) expects ISomethingBN (ISomethingB<number>) but accepts ISomethingBS (ISomethingB<string>)

Answer №1

For those seeking errors, it is essential to utilize the generic T parameter within both ISomethingA and ISomethingB. Merely passing it as another generic parameter without actual utilization will not result in errors due to the structural nature of the type system and the compatibility of types.

As stated in the FAQ: "It is advised to never leave a type parameter unused. Doing so may lead to unexpected compatibility issues (as demonstrated here) and could hinder proper generic type inference in function calls."

Below is the code that triggers the expected errors:

interface IValueA {
  fooA(): void;
}

interface IValueB {
  barB(): void;
}

interface ISomethingA<T> {
    goToB(thing: ISomethingB<T>): void;
    t: T[];
}

interface ISomethingB<T> {
  goToA(thing: ISomethingA<T>): void;
    t: T[];
}

interface ISomethingAS extends ISomethingA<string> {}
interface ISomethingAN extends ISomethingA<number> {}

interface ISomethingBS extends ISomethingB<string> {}
interface ISomethingBN extends ISomethingB<number> {}

export class SomethingA<T> implements ISomethingA<T> {
  public goToB(thing: ISomethingB<T>): void {
    console.log("SomethingA", "goToB", thing);
  }
  t = [];
}

export class SomethingAN implements ISomethingAN {
  public goToB(thing: ISomethingBN): void {
    console.log("SomethingA", "goToB", thing);
  }
  t = [];
}

export class SomethingAS implements ISomethingAS {
  public goToB(thing: ISomethingBS): void {
    console.log("SomethingA", "goToB", thing);
  }
  t = [];
}

export class SomethingB<T> implements ISomethingB<T> {
  public goToA(thing: ISomethingA<T>): void {
    console.log("SomethingA", "goToA", thing);
  }
  t = [];
}

export class SomethingBN implements ISomethingBN {
  public goToA(thing: ISomethingAN): void {
    console.log("SomethingA", "goToA", thing);
  }
  t = [];
}

export class SomethingBS implements ISomethingBS {
  public goToA(thing: ISomethingAS): void {
    console.log("SomethingA", "goToA", thing);
  }
  t = [];
}

const a = new SomethingA<IValueA>();
const b = new SomethingB<IValueB>();

const as = new SomethingAS();
const an = new SomethingAN();

const bs = new SomethingBS();
const bn = new SomethingBN();

a.goToB(b); // error

as.goToB(bn); // error
an.goToB(bs); // error

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

I prefer not to run the next.js SWR until after the initial rendering

Development Setup ・ next.js ・ typescript ・ swr This uses swr for communication purposes. I am looking to only trigger it when the query value changes. However, it is also being executed during the initial rendering. How can I prevent it ...

Implement the click event binding using classes in Angular 2

If I have the template below, how can I use TypeScript to bind a click event by class? My goal is to retrieve attributes of the clicked element. <ul> <li id="1" class="selectModal">First</li> <li id="2" class="selectModal">Seco ...

Ways to retrieve a variable from a separate TypeScript document

A scenario arises where a TypeScript script contains a variable called enlightenFilters$: import { Component, Input, OnInit } from "@angular/core"; import { ConfigType, LisaConfig } from "app/enrichment/models/lisa/configuration.model"; ...

I'm looking for a way to modify my standard function so that it can receive warnings

Below is my function called defc export function defc<T extends Record<string,any> >(f:(a:T)=>void){ return function(a:T){ return f(a) } } The purpose of this function is to ensure the correct return type of func ...

What is the process for turning off a TypeScript rule for a single line of code?

Dealing with Summernote as a jQuery plugin has been a bit of a struggle for me. I'm trying to modify the object without needing type definitions, but TypeScript keeps throwing errors my way. Even after attempting to delete certain keys, I still get th ...

What are the differences between TypeScript's 'Dictionary' type accessors for objects and objects with predefined members?

Currently, I am delving into TypeScript by following an online tutorial. While my programming background primarily consists of 'structurally' typed languages like C and ActionScript 3, TypeScript presents some new concepts for me to grasp. One p ...

Issue "unable to use property "useEffect", dispatcher is undefined" arises exclusively when working with a local npm package

I am currently in the process of creating my very own private npm package to streamline some components and functions that I frequently use across various React TypeScript projects. However, when I try to install the package locally using its local path, ...

What is the best way to grasp the connections between the any, unknown, {} data types and their relationships with other types?

Seeking to comprehend relationships between different types, the following code is presented: type CheckIfExtends<A, B> = A extends B ? true : false; type T1 = CheckIfExtends<number, unknown>; //true type T2 = CheckIfExtends<number, {}> ...

The Server Discovery And Monitoring engine has been marked as obsolete

Currently, I am integrating Mongoose into my Node.js application with the following configuration: mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false }).then ...

A guide on applying color from an API response to the border-color property in an Angular application

When I fetch categoryColor from the API Response, I set border-left: 3px solid {{element.categoryColor}} in inline style. Everything is functioning correctly with no development issues; however, in Visual Studio, the file name appears red as shown in the i ...

Angular 2: Converting JSON data into an array

I am working with JSON data that contains vendor fields and I need to extract unique vendors into an array. Can someone provide guidance on how to achieve this in an Angular2 component? Here is the sample data: [{"category": "Living Room", "vendor": "Fle ...

Tips for Disabling ML5 Posenet

Looking to halt Posenet after completing app task private sketch(p: any) { p.setup = () => { this.poseNet = ml5.poseNet(p.createCapture(p.VIDEO), { outputStride: 8 }); this.poseNet.on(&apos ...

What is the best way to retrieve the post JSON data in the event of a 404 error?

When my service call returns a 404 error, I want to display the server's message indicating the status. The response includes a status code and message in JSON format for success or failure. This is an example of my current service call: this._trans ...

Issues with the update of class properties in Node.js using Express

I am facing some challenges with a .js Object's attribute that is not updating as expected. Being new to the world of JavaScript, I hope my problem won't be too difficult to solve. To begin with, here is a snippet from my Node class: Node = fu ...

Unsynchronized state of affairs in the context of Angular navigation

Within my Angular project, I am currently relying on an asynchronous function called foo(): Promise<boolean>. Depending on the result of this function, I need to decide whether to display component Foo or Bar. Considering my specific need, what woul ...

The Axios GET method retrieves a response in the form of a string that represents an object

I have developed a function that triggers an axios Request. I am working with typescript and I am avoiding the use of any for defining return data types of both the function and the axios request itself. The issue arises when the returned object contains ...

Typed NextJs navigation to a specific route

<Link href="/about"> <a>About Us</a> </Link> Is there a way to ensure type safety with NextJs links? Currently, it is challenging to restructure the Link component as it is just a string. I stumbled upon this repos ...

Here is a guide on implementing Hash in URLs with React Router

I'm brand new to React and running into an issue. My page has two tabs and I would like to create a hash URL that will redirect to the corresponding tab based on the URL hash. Additionally, when I change tabs, I want the URL to update as well. Please ...

Evaluating function declaration - comparing interface to type alias

Here is a function that I need to create a validator for: function (n: number) { return {s: n}; } I have come across two options for creating the validator: Option 1: Interface interface ValidatorFnInterface { (n: number): { [key: strin ...

How can I ensure my function waits for a promise to be resolved using Async / Await?

I'm running into an issue where I want my function to keep executing until the nextPageToken is null. The problem occurs when the function runs for the first time, it waits for the promise to resolve. However, if there is a nextPageToken present in th ...