Description
This proposal allows the Typescript language service to automatically refactor code that uses Promise methods such as .then()
or .catch()
to instead use the async
and await
keywords.
Async/await offers many advantages over promise methods including cleaner syntax, error handling, debugging, and readability. The benefits of the synchronous style code provided by async/await are largely recognized by the Javascript community. However, there is still a substantial amount of asynchronous code written using Promises. This proposal will provide a quick and simple transition to using the async/await keywords.
Simple Examples
Input:
function ex1(): Promise<boolean> {
return fetch('https://microsoft.com').then( result => result.ok; );
}
Output:
async function ex1(): Promise<boolean> {
let result = await fetch('https://microsoft.com');
return result.ok;
}
onRejected handlers:
Input:
function ex2(): Promise<void> {
return fetch('https://microsoft.com').then( result => console.log(result), rej => console.log("error", rej) );
}
Output:
async function ex2(): Promise<void> {
let result;
try {
result = await fetch('https://microsoft.com');
}
catch (rej) {
return console.log("error:", rej);
}
return result.ok;
}
Note that this conversion does not preserve semantics. In order to create clean, readable code, the semantics of some code is slightly altered.
Catch handlers:
Input:
function ex3():Promise<void> {
return fetch('https://microsoft.com').then(result => console.log(result)).catch(err => console.log(err));
}
Output:
async function ex3():Promise<void> {
let result;
try {
result = await fetch('https://microsoft.com');
await console.log(result);
}
catch (err) {
await console.log(err);
}
}
More Examples - multiple handlers
Multiple .then() calls:
In situations where variable names intersect, a new variable name will be chosen for intermediate variables. For example:
Input:
function ex4():Promise<boolean> {
return fetch('https://microsoft.com').then(res).then(res2);
}
function res(result){
return result.ok;
}
function res2(result){
console.log(result);
}
Output:
async function ex4():Promise<boolean> {
let result = await fetch('https://microsoft.com');
let temp = await res(result);
return res2(temp);
}
function res(result){
return result.ok;
}
function res2(result){
console.log(result);
}
Multiple .catch() calls
Input:
function ex5(): Promise<void> {
return fetch('https://microsoft.com').then(res => console.log(res)).catch(err => console.log("err")).catch(err2 => console.log("err2", err2));
}
Output:
async function ex5(): Promise<void> {
try {
let res;
try {
res = await fetch("https://microsoft.com");
return console.log(res);
}
catch (err) {
return console.log("err");
}
}
catch (err2) {
return console.log("err2");
}
}
More Examples - Promise.all() and Promise.race()
In order to preserve semantics, code that uses Promise.all()
cannot be entirely refactored.
Input
function ex6():Promise<void> {
return Promise.all([fetch('https://microsoft.com'), fetch('https://microsoft.com'), fetch('https://youtube.com')]).then(
function(vals){
vals.forEach(console.log);
});
}
Output:
async function ex6():Promise<void> {
let vals = await Promise.all([fetch('https://microsoft.com'), fetch('https://microsoft.com'), fetch('https://youtube.com')]);
return vals.forEach(console.log);
}
Similarly, code that uses 'Promise.race()' is partially refactored:
Input
function ex7():Promise<void> {
return Promise.race([fetch('https://microsoft.com'), fetch('https://microsoft.com'), fetch('https://youtube.com')]).then(val => console.log(val));
}
Output:
async function ex7():Promise<void> {
let val = await Promise.race([fetch('https://microsoft.com'), fetch('https://microsoft.com'), fetch('https://youtube.com')]);
return console.log(val);
}
More Examples - Returning variables of Promise type
In order to preserve semantics, a refactoring will only be offered for functions that directly return a promise with callbacks.
For example, a refactoring will not be offered for the following:
function ex8() {
let blob = fetch("https://typescriptlang.org").then(resp => console.log(resp));
return blob;
}
However, a refactoring will be offered for the following function as it can be converted to use async and await while preserving semantics:
function ex9() {
return fetch("https://typescriptlang.org").then(resp => console.log(resp));
}
Support for .finally()
will be coming later