What is the best way to ensure type safety in a Promise using Typescript?

It seems that Promises in Typescript can be type-unsafe. This simple example demonstrates that the resolve function accepts undefined, while Promise.then infers the argument to be non-undefined:

function f() {
  return new Promise<number>((resolve) => {
    resolve(undefined)
  })
}

f().then((value) => { 
  console.log(value+1)
})

(tested in my current project and on ).

Currently, Typescript interprets the type of value as number instead of

number | PromiseLike<number> | undefined
.

This issue may be specific to Typescript at the moment, but...

What is a suitable workaround? I want the compiler to alert me if value could be undefined!

A straightforward solution could be:

f().then((value:number | undefined) => { 
  console.log(value+1) // now I get: Object is possibly 'undefined'
})

However, this means having to consciously address the problem every time it's called.

EDIT (current status): Following the solution provided by @JerMah, I encapsulated the creation of the Promise within a generic function:

function makePromise<T>(executor: (resolve: (value: T) => void,
                                   reject: (reason?: any) => void) => void)
{
  return new Promise<T>(executor);
}

Answer №1

One way to ensure you do not pass undefined to the resolve function is by manually setting its signature.

function f() {
  return new Promise<number>((resolve: (arg0: number) => void) => {    
    resolve(undefined); // Argument of type 'undefined' is not assignable to parameter of type 'number'.
  });
}

TypeScript playground

Answer №2

Regrettably, the current version of TypeScript does not support this feature. However, with a bit more verbosity, you can modify your code like so:

const iReturnUndefined = () => undefined

function f() {
    return new Promise<number>((resolve) => {
        const resolvedVal: number = iReturnUndefined() // Type 'undefined' is not assignable to type 'number'.

        resolve(resolvedVal)
    })
}

TypeScript playground

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

Get information collectively in node.js

How can I retrieve 10 records from a MongoDB collection using NodeJs, with each batch containing 10 records? ...

Minimize the cyclomatic complexity of a TypeScript function

I have a typescript function that needs to be refactored to reduce the cyclometric complexity. I am considering implementing an inverted if statement as a solution, but it doesn't seem to make much of a difference. updateSort(s: Sort) { if (s.ac ...

I encountered an unexpected token error while using JavaScript syntax with objects

In my current coding project, I have encountered an issue while attempting to utilize an object from a different JavaScript file. Despite importing the necessary function from this external file, there seems to be a syntax error present. Can anyone offer ...

Embedding image URLs fetched from JSON data within <li> elements

I have successfully retrieved a JSON response, which is displayed using the code below: Within my HTML document, I have the following structure: <ol id="selectable"></ol> In my JavaScript code, I make use of the following: <script type=" ...

The service that offers an Observable on a specific subject is not receiving any notifications

The EventSpinner component is designed to subscribe to icons provided by the EventsService. @Component({ selector: 'event-spinner', template: ` <div class="col-xs-5"> Test <i class="fa fa-2x" [ngClass]="{'fa-check' ...

Choose the dropdown item depending on the related text

I am currently working on a drop-down menu where each option has a value and associated text. The selected option is then displayed row by row in a table, with an edit button next to each row that allows the user to change the selection. I am trying to imp ...

Error: The function res.getHeader is not recognized within the Next.js API environment

I am currently working on a web application using NextJS 13, TypeScript, Next Auth v4, Prisma (using SQLite for development), and OpenAI. While accessing the API endpoint, I encountered an error in the console with the following message: error - TypeError ...

The class-transformer malfunctioning: The transformation function is not being executed

I am facing an issue with implementing class-transformer in my codebase, despite using type-graphql and @typegoose/typegoose libraries. Below is the snippet of my code: Custom Decorator import { Transform } from 'class-transformer'; export func ...

Tips on incorporating toggle css classes on an element with a click event?

When working with Angular typescript instead of $scope, I am having trouble finding examples that don't involve $scope or JQuery. My goal is to create a clickable ellipsis that, when clicked, removes the overflow and text-overflow properties of a spec ...

Choose between creating an observable pipe within a function or storing it in a variable

Currently, I have a functional code snippet that leverages the Angular service to create an Observable pipeline. This pipeline utilizes operators like mergeMap, filter, map, and shareReplay(1) to manage user authentication and fetch the onboarding status f ...

Can you provide guidance on the most effective approach to appending to a file using async await?

Is it safe to repeatedly call functions like fs.appendFile()? For instance, when using child_process.spawn and a "for-async-of" loop to implement tee with JavaScript. Chunked file data needs to be appended to a file while performing other processing. If ap ...

How to encase HTML content within a scope variable without relying on ng-bind-html

Is there a way to include HTML content using a scope variable in AngularJS without utilizing ng-bind-html-unsafe? <div ng-controller="dataController">{{test}}</div> $scope.test = "<div>Html content</div>" ...

Using Promise to manipulate objects and arrays returned from functions

https://i.stack.imgur.com/jvFzC.png router.get('/', function (req, res, next) { var size = req.params.size ? parseInt(req.params.size) : 20; var page = req.params.page ? req.params.page>0 ? (size&(parseInt(req.params.page)-1)) : ...

Can one transition from using a callback to a returning Promise in order to implement an ErrorFirstCallback strategy?

In Node.js documentation, it is explained that an ErrorFirstCallback is triggered when the referred function fails. Error-first-callbacks in Node.js I have been practicing with this callback pattern and I am curious to know if it is possible to refactor i ...

Using type values in TypeScript

I am trying to assign interfaces as values within a config object: export interface RouterConfig { startEvents?: typeof RouterEvent[]; completeEvents?: typeof RouterEvent[]; } The intended usage is as follows: private config: RouterConfig = { star ...

Is it feasible to restrict a generic type using typeguard?

I'm currently working on refining a generic function, where the autocomplete feature recognizes that it's encountering a typeguard, preventing it from revisiting the same code block. I suspect that the issue lies in not restricting the type to th ...

Tips for implementing a draggable image within an <a-scene> by utilizing <a-assets> and <a-image> tags

Exploring the world of augmented reality for the web has been an interesting journey for me. I have been experimenting with aframe-ar.js and aframe.js to create a unique experience. One of the challenges I faced was making an image draggable within the & ...

Troubleshooting: Success with AJAX call in Chrome, but issues in IE

Having issues retrieving JSON data from a URL that displays the last 3 numbers of a webpage. The AJAX call functions correctly in Google Chrome but fails in Internet Explorer. I tried disabling caching using cache: false as suggested, but the problem persi ...

Using Jquery and Ajax to add information to a database

One of the challenges I'm facing involves a page with three forms, each containing separate variables that need to be inserted into a MySQL database for viewing. My current script is working fine, even though I am aware that `mySql_` is deprecated but ...

Unable to locate "Gruntfile.js" Node module for task execution

I am currently in the process of developing a module that enables node to execute Grunt tasks via the command line. This Node module is globally installed at : C:\Users\pcharpin\AppData\Roaming\npm\node_modules\task-app ...