Issue with TypeScript while trying to define a property of a named function expression using 'let' instead of 'const'

As I continued my journey through the TypeScript handbook, I stumbled upon an intriguing concept while learning about Call Signatures. The code snippet provided in the handbook goes like this:

type DescribableFunction = {
 description: string;
 (someArg: number): boolean;
};

function doSomething(fn: DescribableFunction) {
 console.log(fn.description + " returned " + fn(6));
}

I decided to experiment by creating a function that could be executed by doSomething. However, I encountered a perplexing issue when trying to define the function as a named expression using let. It gave me an error stating

"Property 'description' does not exist on type '(n: number) => boolean'.(2339)"
while assigning the description property. Strangely, defining the function as a function declaration or with const allowed me to assign the property without any issues... Why is that?

Take a look at the example below for clarification.

type DescribableFunction = {
  description: string;
  (someArg: number): boolean;
};

function doSomething(fn: DescribableFunction) {
  console.log(fn.description + " returned " + fn(6));
}

function f(n:number){
  return true;
}

f.description = "bla bla bla";

let testFunc = function f(n: number) {
    return true;
}

testFunc.description = "bla bla bla"; //This shows an error!!

const testFunc2 = function f(n: number) {
    return true;
}
testFunc2.description = "bla bla bla";

Answer №1

With the release of TypeScript 3.1, a new feature was introduced which allowed for declaring properties on functions, as seen in the GitHub pull request microsoft/TypeScript#26368. This update now enables developers to

define properties on function declarations and const-declared functions

This functionality can be observed in examples like `f` and `testFunc2`. Prior to TypeScript 3.1, these examples would have thrown errors. It's worth noting that property declarations are not available for functions declared with `let`. Unfortunately, there is no clear explanation provided in the GitHub documentation or release notes.


To support functions declared with `let` or `var`, the compiler would need to handle the possibility of functions being reassigned, adding complexity to tracking such changes. For instance, declaring:

testFunc = () => false; // okay

would require the compiler to analyze if and when `testFunc` gains a `description` property through control flow analysis. On the other hand, functions declared using `function` statements or `const` variables cannot be reassigned, eliminating the need for such intricate control flow considerations.

In light of this, it is speculated that property declarations on reassignable functions were not included due to the added difficulty in implementation, compounded by the lack of demand for this specific feature.

Click here to access the Playground link for code examples

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

Swap out a specific object within an observable array by comparing object properties

Currently, I am retrieving an observable array of custom IPix objects (Observable<IPix[]>) from a database using an API. After that, I update a record in the database by sending an edited version of the IPix object back to the API through a PUT reque ...

Utilizing asynchronous JavaScript imports within exported classes

Currently, I have a package with async/dynamic exports that I import in the following manner: (async function() { const libEd = await import("../../.cache/ed25519wars/index.js"); })(); I plan to re-expose certain functions from libEd within a class str ...

Guide to using Enums in *ngIf statements in Angular 8

I have defined an enum type in my TypeScript file, and I want to use it as a condition in my HTML code. However, when trying to access the "values" of the enum, they appear to be undefined even though I have declared them and inherited from the exported en ...

Tips for transforming alphanumeric characters into value ranges using Typescript

myArray = ["AB01","AB02","AB03","AB04","AB11","BC12","BC13", "SB33"]; // code snippet to create expected string: "AB01-AB04, AB11, BC12-BC13, SB33" The array contains combinations of one or two letter characters followed by two or three digits. Examples ...

Customizing the HTMLElement class to modify particular attributes

Is there a way to modify the behavior of an HTMLElement's scrollTop property by adding some extra logic before updating the actual value? The common approach seems to be deleting the original property and using Object.defineProperty(): delete element. ...

A guide on how to retrieve images from a URL and save them using Blob in Angular 5

In my web application, I have a few links that lead to files with different content types - some are application/pdf and others are image/jpeg. When clicking on these links, the file should download or save based on their respective type. While downloadin ...

Attempting to locate a method to update information post-editing or deletion in angular

Are there any methods similar to notifyDataSetChange() in Android Studio, or functions with similar capabilities? ...

Exploring the representation of recursive types using generic type constraints

Is there a way to create a structure that can handle recursive relationships like the one described below? I am looking to limit the types of values that can be added to a general container to either primitive data types or other containers. Due to limit ...

Retrieve: Type 'string | undefined' does not match the parameter type 'RequestInfo'

When using the fetch function, I encountered an error with the "fetchUrl" argument: Error: Argument of type 'string | undefined' is not assignable to parameter of type 'RequestInfo'. This is the code snippet where the error occurred: ...

Creating a Fixed HeaderToolbar in FullCalendar React

I am currently working on customizing the FullCalendar React component and I am looking to incorporate a sticky headerToolbar. My main objective is to have the header along with its toolbar remain fixed at the top of the calendar, even when users scroll th ...

Managing multiple Sequelize DB connections in NestJS: A guide

I recently came across the example in the NestJS documentation regarding setting up a Sequelize DB connection. I'm curious about how to connect to multiple databases using Sequelize and TypeScript with NestJS. Can anyone provide guidance on this? ...

Is it possible to validate a template-driven form without using the model-driven approach?

Attempting to validate a template-driven form in Angular without two-way data binding has proved to be challenging. I have successfully implemented validation using [(ngModel)], but running into an error when trying to validate the form without the MODEL p ...

Setting up ESLint and Prettier with TypeScript on Node 20: A Guide

I attempted to set up Prettier with ESLint and crafted a configuration in settings.json to rectify errors upon saving, but the errors only manifest in .js files and not .ts files. How can I adjust this? Dependencies: "@eslint/js": "^9.4.0& ...

The challenge of extending a TypeScript generic to accept an Array type with unrelated elements

I have a function that resembles the following mock: // All properties in this type are optional. interface MyType { a?: string } // The return result type of `cb` is kept as the final result type. const f = <T extends ReadonlyArray<MyType>> ...

What is the equivalent of a "Class" in Typescript for defining an "Interface"?

I am interested in passing "Interfaces" to a function. Not just a specific interface, but any interfaces. As explained here, for Class, I can handle it as a type. export type ClassType<T> = { new(...args: any[]): T }; function doSomethingWithAnyCla ...

Struggling with extracting an array of objects from a JSON file and accessing individual attributes within each object?

As a newcomer to Typescript, I am eager to work with JSON and access its objects and attributes. However, I am encountering difficulties in achieving this. I have attempted using functions like 'for of' and 'for in', but unfortunately, ...

I am facing an issue with the Angular2 Modal Form where it only displays the data but does

Hey there, I recently started diving into Angular and I'm loving the learning process. Currently, I've managed to successfully load a form into my Modal when clicking on "viewDetails". However, as soon as I modify the Form from <form ngNoFo ...

The Angular material checkbox has a mind of its own, deciding to uncheck

I am having an issue with a list displayed as checkboxes using angular-material (Angular 7). Below, I will provide the code snippets for both the .html and .ts files. Every time I click on a checkbox, it gets checked but then immediately becomes unchecked ...

How can RxJS be used to handle only the first value returned when calling multiple URLs?

I am faced with the challenge of having multiple URLs containing crucial information. My goal is to find a specific ID within these URLs, but I do not know which URL holds the necessary details. The approach I'm taking involves calling each URL and us ...

Exploring methods for interacting with and controlling structural directives in e2e testing

Background: My goal is to permutation all potential configurations of an Angular2 screen for a specified route and capture screenshots using Protractor from the following link: http://www.protractortest.org/#/debugging. Problem: I am struggling to figure ...