The function does not throw a compiler error when a parameter is missing

Currently utilizing TSC Version 2.4.2

Please take note of the following interface:

interface CallbackWithNameParameter {
  cb: (name: string) => void
}

This code snippet:

const aCallback: CallbackWithNameParameter = {
  cb: () => {}
};

Manages to run without triggering a compile error, despite expectations.

It is worth mentioning that this portion does indeed cause an error:

const aSecondCallback: CallbackWithNameParameter = {
  cb: (num: number) => {}
};

Could this be considered a bug within TSC or is there a misinterpretation on my end? Shouldn't aCallback raise a compile error?

Answer №1

It's important to note that in TypeScript, a function with fewer trailing parameters can be substituted for a function with more trailing parameters as long as the parameter types match. This concept is explicitly addressed in the TypeScript FAQ due to its common occurrence.

The rationale behind this is that any function in JavaScript can be called with any number of parameters, and it is always safe for a caller to send more parameters than expected to a function - the extra parameters are simply ignored. For example:

const aCallback: CallbackWithNameParameter = {
  cb: () => {}
};

This code snippet is valid because the aCallback.cb function ignores the first parameter (which must be a string). However, the following case with aSecondCallback would be invalid as it attempts to interpret the first parameter as a number instead of a string, potentially leading to errors.


That pretty much covers the basics. Good luck!


Update 1

In response to an inquiry by @jbmilgrom, about why aCallback.cb() results in a compile error although its definition seems correct, the explanation lies in the declaration of the type

CallbackWithNameParameter</code for <code>aCallback
. Essentially, TypeScript enforces type constraints based on the declared types, not on actual values, which causes the compile error in this scenario.

A workaround would involve defining a separate interface like so:

interface CallbackWithNoParameter {
  cb: () => void
}

const aCallback: CallbackWithNoParameter = {
  cb: () => {}
};
aCallback.cb(); // this works fine

Regarding substitutability, while you can assign a narrower type to a wider type without issue, attempting the reverse generally results in a compilation error.


Update 2

@jbmilgrom further questioned why TypeScript allows defining something that can never be invoked as defined, pointing out inconsistencies in how substitutable types are handled. The analogy used here likens pouring milk into a container labeled "liquid" (wider type), then expecting it to act like milk when poured into tea, highlighting the confusion caused by type declarations.

To better handle such scenarios, creating explicit type differentiations rather than relying solely on broader types is recommended. Checking if a function accepts zero arguments without causing runtime issues can be challenging, as shown in the provided code snippet.

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

Use the bind method to wrap console.log and preserve the calling context

When it comes to logging message text while preserving the original context (class, line number), console output does the job perfectly with console.log.bind(console). However, the challenge arises when I also need to send the message to an HTTP server for ...

Is the child constantly updating due to a function call?

Having difficulty navigating the intricacies where a child keeps re-rendering due to passing a function from the parent, which in turn references an editor's value in draftjs. function Parent() { const [doSomethingValue, setDoSomethingValue] = Re ...

The error message "Unable to find 'encoding'" in NextJS is triggered by the use of try/require in the node_modules folder

Running a NextJS app in typescript with version 13.4.19, utilizing @apollo/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0d7e687f7b687f4d392334233e">[email protected]</a> triggers a warning during the build proce ...

Showing the outcome of the request from the backend on an HTML page using the MEAN stack

I am currently in the process of developing an angular application with a node.js + express backend. After successfully retrieving the necessary data from MongoDB and being able to view it through terminal, I encountered a challenge when trying to display ...

Utilizing the "as" keyword for type assertion in a freshly created react application using create-react-app leads to the error message `Parsing error: Unexpected token, expected ";"`

After creating a new CRA project using yarn create react-app my-app --template typescript, I encountered an error when trying to run the development server with yarn start: src/App.tsx Line 5:24: Parsing error: Unexpected token, expected ";" ...

What is the best way to merge an array into a single object?

I have an array object structured like this. [ { "name": "name1", "type": "type1", "car": "car1", "speed": 1 }, { "name": &q ...

I'm facing difficulty in assigning props because of the specific nature of generics in Typescript

My goal is to create a Higher Order Component (HOC) that can control a component which relies on certain props to function properly. To elaborate: I want to build a HOC that takes a component expecting props value and onChange, and modifies it so that the ...

An example in Typescript for setting an initial/default value for a data type

Can you create a Type with a default value included? For example: type Animal = { kind : "animal" Legs : number, CanFly: boolean } const monkey: Animal = { Legs: 4, CanFly: false}; //In this line, clients must initialize the same value `kin ...

Expressjs makes it easy to upload audio files to your website

Currently, I'm developing a music app and I'm looking for the best way to upload an audio file in my ExpressJS application. Is it possible to use Cloudinary or is there another method that is more efficient? I attempted to follow the same proces ...

Triggering an event within a component to execute a specific function in another component

I am working on a component that includes multiple routes such as home, app, and navbar. My goal is to have the encrementcalc() function execute when the navbar button is pressed. I attempted to use the event emitter but was unsuccessful. Can someone prov ...

Autocomplete feature in MUI allows filtering to begin after typing at least 3 characters

I've encountered an issue with the Autocomplete MUI component I'm using to filter a list of checkboxes. The popup with options should remain open at all times, but I only want the filtering to be triggered when the user input is more than 3 chara ...

Join the Observable in Angular2 Newsletter for the latest updates and tips

One of my functions stores the previous URL address. prevId () { let name, id, lat, lng; this.router.events .filter(event => event instanceof NavigationEnd) .subscribe(e => { console.log('prev:', this.previo ...

activeStyle is not a valid property for type 'IntrinsicAttributes'

I encountered an issue while attempting to utilize NavLink in a react typescript project. The error message states: "Property 'activeStyle' does not exist on type 'IntrinsicAttributes & NavLinkProps & RefAttributes'." import Rea ...

Error in ThreeJS: Unable to execute material.customProgramCacheKey

I encountered an issue TypeError: material.customProgramCacheKey is not a function The error pops up when I invoke the function this.animate(). However, no error occurs when the URL is empty. Where could this error be originating from since I don't ...

Tips for sending multiple post parameters to a web API in Angular using TypeScript

I am looking to send multiple values to a web API using AngularJS TypeScript. // POST api/values public void Post([FromBody]string value1, [FromBody]string value2) { } I want to make the method call like this: $http.post('api/values', ???) I ...

Utilize the useState hook to update state when changes occur in the

I currently have a functional component that utilizes a useState hook. The values it holds are sourced from my redux store, and I aim to update the state with the new store state every time an action is dispatched. At the moment, I've manually set an ...

"What is the best way to determine the data type of an object retrieved from an API in TypeScript

Hey there, I'm currently developing a web application using Angular 2 and I'm focusing on implementing an exception handling mechanism. To achieve this, I've created a model that mirrors the object structure I will receive from the server (E ...

Preserving variable values across page transitions in Angular 2

I am facing an issue with my multi-page website that uses a router. I want to pass a variable value from one page to another. Here is the code snippet from my contact form page: testName:string = "hello"; ngOnInit() { this.dataService.Stream ...

What is the best way to ensure an observable has been updated before proceeding with additional code execution?

Is an observable the best choice for providing live updates of a variable's value to another class? I have a loop in my service class that looks like this: elements.forEach(element => { doStuff(); this.numberSubject.next(valueFromDoStuff); }) ...

@Viewchild doesn't have access to matSort

In my Angular project, I am having trouble getting my @ViewChild instance to work with MatSort in HTML. component.ts file: import { MatSort } from '@angular/material'; export class MyComponent { @ViewChild(MatSort) sort: MatSort; } ngOn ...