Should compile time errors be triggered by generic function constraints?

Surprisingly, the following code does not throw a compile time error as expected.

interface Service {
}

abstract class TestService implements Service {
}

class TestServiceImpl extends TestService {

}

class Blah {

}

function getService<T extends Service>(service: T): string {
    return 'hello';
}

let m = getService( Blah );

The compiler allows a type that doesn't extend Service to be passed into getService, even though the T extends Service constraint should prevent this. Any thoughts on why?

EDIT

I tried giving getService a proper body that references its parameter but it didn't change anything.

Adding something to the Service interface did make a difference, which is different from my experience with other languages.

Now there's an error in the following code, just not the one I was expecting:

interface Service {
    doSomething(): number;
}

abstract class TestService implements Service {
    public doSomething(): number {
        return 1;
    }
}

class TestServiceImpl extends TestService {
    public doSomethingElse(): void {
        //
    }
}

function getService<T extends Service>(service: T): string {
    return (<any>service).name;
}

let m = getService( TestService );

Now I get the error:

error TS2345: Argument of type 'typeof TestService' is not assignable to parameter of type 'Service'. Property 'doSomething' is missing in type 'typeof TestService'. let m = getService( TestService );

But isn't TestService supposed to implement Service?

Feeling a bit perplexed here

Answer №1

getService(Blah) function, it is passing in the declaration of Blah, which seems to be just a function. To correctly pass it, you should use getService(new Blah).

In TypeScript, types can extend each other without needing explicit declarations. The check is made based on interface conformity. Since Service has no properties, it will pretty much accept anything. You could even call getService(1) or getService(false) and TypeScript won't throw an error.

For instance, you can write:

let blah: Service = new Blah(); getService(blah)
. TypeScript handles coercion for you.

If Service had properties, then Blah would need to match those properties:

interface Service { a: string; }
class Blah { }
getService(new Blah()); // error - Type 'Blah' is not assignable to type 'Service'
class BetterBlah { a: string; }
getService(new BetterBlah()); // works -- interfaces conform

This means that interfaces in TypeScript serve as suggestions. This flexibility is likely due to JavaScript interoperability and object variable declarations. For example, with the Service type mentioned above, you could also do:

getService({ a: 'value' });

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

Using a Fake Timer to test the setTimeout function for a class method is not possible

One way to test setTimeout with a normal function is by using the following code: function doAsync() { setTimeout(doAsync, 1000) } jest.useFakeTimers() test("setTimeout with function", async () => { doAsync() jest.advanceTimersByTime(2 ...

How to minimize scaffolding with Redux, React, and Typescript?

Is there a way to avoid the process of instrumenting my Redux-Aware components? The level of scaffolding required seems excessive. Take, for instance, the minimal code necessary to define a redux-aware component: class _MyActualComponent extends React.Co ...

The pagination in React using React Query will only trigger a re-render when the window is in

Currently, I am utilizing React-Query with React and have encountered an issue with pagination. The component only renders when the window gains focus. This behavior is demonstrated in the video link below, https://i.sstatic.net/hIkFp.gif The video showc ...

Placing a MongoDB query results in an increase of roughly 120MB in the total JS heap size

I'm puzzled by the fact that the heap size increases when I include a MongoDB database query in a function within my controller. Here is the code for my router: import { Router } from "express"; import profileController from '../contro ...

The incorrect initial state is causing issues in the Zustand state management on the Next.js server side

While utilizing zustand as a global state manager, I encountered an issue where the persisted states were not being logged correctly in the server side of nextjs pages. The log would only show the default values (which are null) and not the updated state v ...

Using Typescript with d3 Library in Power BI

Creating d3.axis() or any other d3 object in typescript for a Power BI custom visual and ensuring it displays on the screen - how can this be achieved? ...

Ways of invoking a component method from a service in Angular 2

I have a concept for creating a unique service that is capable of interacting with one specific component. In my application, all other components should have the ability to call upon this service and then have it interact with the designated component in ...

Tracking code execution in React, Enzyme, and Istanbul reveals uncovered functions running during tests

I have been working on testing a React component that involves 3 functions. The tests I've written for these functions pass successfully, but my code coverage report indicates only a 33% coverage. Here is the code snippet of the component: const AddW ...

Troubleshooting d3js Type Errors in Angular (Updated Version)

Encountering numerous type errors with d3js when integrating it into Angular (typescript). svg.call(d3.zoom().on('zoom', () => { g.attr('transform', d3.events.transform); })); Error thrown: S2345: Argument of type 'Zo ...

How can I stop the input field from clearing when using material-ui TextField with datetime-local type?

When you run the code below and only enter a date, the rendering process will occur and clear the date input. This specific TextField is designed to serve as a search parameter for this component. import * as React from 'react' import { TextFie ...

Incorrect tsx date interpretation when dealing with years such as 0022

I am facing an issue with dates in tsx. The problem lies in the fact that when I set a date like 30/11/0022, it interprets the date as 30/11/1922, which is incorrect. Here is the input element I have in tsx: <FormikField name="Birthdate" disa ...

Utilize apexcharts to apply custom colors for negative data points

I am currently utilizing apex charts within a react application, and I have a requirement to display markers with different colors if the y value is a negative number. Below is the logic that I am using to extract the values: const colorMarkers = ...

Troubleshooting Issue: Angular 6 - Authentication token interceptor not including headers

After experimenting with various approaches using Angular 6 for the past couple of days, I recently tried implementing a solution mentioned in this post: . Despite my efforts, the header in the requests still remains unset. import {Inject, Injectable} fro ...

Dealing with code in Angular when transitioning to a different component

I have an Angular component that displays data and includes a button called "Go to Dashboard". I want to implement a feature where the user can either click on this button to navigate to the dashboard or have the application automatically redirect them aft ...

Tips for soothing the TypeScript compiler

It seems like TypeScript is heavily influenced by Microsoft's interpretation of the DOM and JavaScript. But what if I'm not concerned with Internet Explorer and Edge? Unfortunately, I'm encountering issues with TypeScript... For instance, w ...

Enhancing the express Response Object with Typescript in a structured manner

Currently, I am immersed in a project that utilizes Typescript 3+, express 4+, and node 8+. My main objective is to augment the express Response object to handle HTTP status codes when an error is detected within an API. However, I am facing challenges in ...

Creating a Typescript empty object to manage state in a React component

I'm currently working on creating a type for a specific object that has the possibility of being empty. Let's start by defining the state for our React class, beginning with the CharacterInventoryTabsState interface: export default interface Char ...

Compiling with tsc --build compared to tsc --project

I'm currently working on converting a subproject to TypeScript within my monorepo. Within my npm scripts, I initially had: "build-proj1":"tsc --build ./proj1/tsconfig.json" Although it did work, I noticed that the process was unus ...

Importing modules that export other modules in Typescript

I am facing an issue with two modules and two classes. ModuleA, ModuleB, ClassA, and ClassB are defined as follows: export class ClassA { } export class ClassB { } The modules are structured like this: export * from './ClassA'; export module ...

Create an alternate name for a specific type of key within a nested record

There are three simple types available: const structureTypes = z.enum(["atom","molecule"]) const atomTypes = z.enum(["oxygen","hydrogen"]) const moleculeTypes = z.enum(["water","ammonia"]) The goal is to define a type for a cache where the keys correspond ...