Only provide suggestion for outermost async fix
This commit is contained in:
parent
4a664d690b
commit
2dd6e20ef9
|
@ -60,7 +60,7 @@ namespace ts.codefix {
|
|||
const setOfExpressionsToReturn = getAllPromiseExpressionsToReturn(functionToConvert, checker);
|
||||
const functionToConvertRenamed = renameCollidingVarNames(functionToConvert, checker, synthNamesMap, context, setOfExpressionsToReturn, originalTypeMap, allVarNames);
|
||||
const constIdentifiers = getConstIdentifiers(synthNamesMap);
|
||||
const returnStatements = functionToConvertRenamed.body && isBlock(functionToConvertRenamed.body) ? getReturnStatementsWithPromiseHandlers(functionToConvertRenamed.body) : emptyArray;
|
||||
const returnStatements = functionToConvertRenamed.body && isBlock(functionToConvertRenamed.body) ? getReturnStatementsWithPromiseHandlers(functionToConvertRenamed.body, checker) : emptyArray;
|
||||
const transformer: Transformer = { checker, synthNamesMap, allVarNames, setOfExpressionsToReturn, constIdentifiers, originalTypeMap, isInJSFile: isInJavascript };
|
||||
|
||||
if (!returnStatements.length) {
|
||||
|
@ -87,10 +87,10 @@ namespace ts.codefix {
|
|||
}
|
||||
}
|
||||
|
||||
function getReturnStatementsWithPromiseHandlers(body: Block): ReadonlyArray<ReturnStatement> {
|
||||
function getReturnStatementsWithPromiseHandlers(body: Block, checker: TypeChecker): ReadonlyArray<ReturnStatement> {
|
||||
const res: ReturnStatement[] = [];
|
||||
forEachReturnStatement(body, ret => {
|
||||
if (isReturnStatementWithFixablePromiseHandler(ret)) res.push(ret);
|
||||
if (isReturnStatementWithFixablePromiseHandler(ret, checker)) res.push(ret);
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
@ -450,7 +450,7 @@ namespace ts.codefix {
|
|||
seenReturnStatement = true;
|
||||
}
|
||||
|
||||
if (isReturnStatementWithFixablePromiseHandler(statement)) {
|
||||
if (isReturnStatementWithFixablePromiseHandler(statement, transformer.checker)) {
|
||||
refactoredStmts = refactoredStmts.concat(getInnerTransformationBody(transformer, [statement], prevArgName));
|
||||
}
|
||||
else {
|
||||
|
@ -466,7 +466,7 @@ namespace ts.codefix {
|
|||
seenReturnStatement);
|
||||
}
|
||||
else {
|
||||
const innerRetStmts = isFixablePromiseHandler(funcBody) ? [createReturn(funcBody)] : emptyArray;
|
||||
const innerRetStmts = isFixablePromiseHandler(funcBody, transformer.checker) ? [createReturn(funcBody)] : emptyArray;
|
||||
const innerCbBody = getInnerTransformationBody(transformer, innerRetStmts, prevArgName);
|
||||
|
||||
if (innerCbBody.length > 0) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/* @internal */
|
||||
namespace ts {
|
||||
const visitedNestedConvertibleFunctions = createMap<true>();
|
||||
|
||||
export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): DiagnosticWithLocation[] {
|
||||
program.getSemanticDiagnostics(sourceFile, cancellationToken);
|
||||
const diags: DiagnosticWithLocation[] = [];
|
||||
|
@ -13,6 +15,7 @@ namespace ts {
|
|||
|
||||
const isJsFile = isSourceFileJS(sourceFile);
|
||||
|
||||
visitedNestedConvertibleFunctions.clear();
|
||||
check(sourceFile);
|
||||
|
||||
if (getAllowSyntheticDefaultImports(program.getCompilerOptions())) {
|
||||
|
@ -114,17 +117,21 @@ namespace ts {
|
|||
}
|
||||
|
||||
function addConvertToAsyncFunctionDiagnostics(node: FunctionLikeDeclaration, checker: TypeChecker, diags: Push<DiagnosticWithLocation>): void {
|
||||
if (!isAsyncFunction(node) &&
|
||||
node.body &&
|
||||
isBlock(node.body) &&
|
||||
hasReturnStatementWithPromiseHandler(node.body) &&
|
||||
returnsPromise(node, checker)) {
|
||||
if (!visitedNestedConvertibleFunctions.has(getKeyFromNode(node)) && isConvertableFunction(node, checker)) {
|
||||
diags.push(createDiagnosticForNode(
|
||||
!node.name && isVariableDeclaration(node.parent) && isIdentifier(node.parent.name) ? node.parent.name : node,
|
||||
Diagnostics.This_may_be_converted_to_an_async_function));
|
||||
}
|
||||
}
|
||||
|
||||
function isConvertableFunction(node: FunctionLikeDeclaration, checker: TypeChecker) {
|
||||
return !isAsyncFunction(node) &&
|
||||
node.body &&
|
||||
isBlock(node.body) &&
|
||||
hasReturnStatementWithPromiseHandler(node.body, checker) &&
|
||||
returnsPromise(node, checker);
|
||||
}
|
||||
|
||||
function returnsPromise(node: FunctionLikeDeclaration, checker: TypeChecker): boolean {
|
||||
const functionType = checker.getTypeAtLocation(node);
|
||||
const callSignatures = checker.getSignaturesOfType(functionType, SignatureKind.Call);
|
||||
|
@ -136,25 +143,25 @@ namespace ts {
|
|||
return isBinaryExpression(commonJsModuleIndicator) ? commonJsModuleIndicator.left : commonJsModuleIndicator;
|
||||
}
|
||||
|
||||
function hasReturnStatementWithPromiseHandler(body: Block): boolean {
|
||||
return !!forEachReturnStatement(body, isReturnStatementWithFixablePromiseHandler);
|
||||
function hasReturnStatementWithPromiseHandler(body: Block, checker: TypeChecker): boolean {
|
||||
return !!forEachReturnStatement(body, stmt => isReturnStatementWithFixablePromiseHandler(stmt, checker));
|
||||
}
|
||||
|
||||
export function isReturnStatementWithFixablePromiseHandler(node: Node): node is ReturnStatement {
|
||||
return isReturnStatement(node) && !!node.expression && isFixablePromiseHandler(node.expression);
|
||||
export function isReturnStatementWithFixablePromiseHandler(node: Node, checker: TypeChecker): node is ReturnStatement {
|
||||
return isReturnStatement(node) && !!node.expression && isFixablePromiseHandler(node.expression, checker);
|
||||
}
|
||||
|
||||
// Should be kept up to date with transformExpression in convertToAsyncFunction.ts
|
||||
export function isFixablePromiseHandler(node: Node): boolean {
|
||||
export function isFixablePromiseHandler(node: Node, checker: TypeChecker): boolean {
|
||||
// ensure outermost call exists and is a promise handler
|
||||
if (!isPromiseHandler(node) || !node.arguments.every(isFixablePromiseArgument)) {
|
||||
if (!isPromiseHandler(node) || !node.arguments.every((arg) => isFixablePromiseArgument(arg, checker))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ensure all chained calls are valid
|
||||
let currentNode = node.expression;
|
||||
while (isPromiseHandler(currentNode) || isPropertyAccessExpression(currentNode)) {
|
||||
if (isCallExpression(currentNode) && !currentNode.arguments.every(isFixablePromiseArgument)) {
|
||||
if (isCallExpression(currentNode) && !currentNode.arguments.every(arg => isFixablePromiseArgument(arg, checker))) {
|
||||
return false;
|
||||
}
|
||||
currentNode = currentNode.expression;
|
||||
|
@ -167,16 +174,24 @@ namespace ts {
|
|||
}
|
||||
|
||||
// should be kept up to date with getTransformationBody in convertToAsyncFunction.ts
|
||||
function isFixablePromiseArgument(arg: Expression): boolean {
|
||||
function isFixablePromiseArgument(arg: Expression, checker: TypeChecker): boolean {
|
||||
switch (arg.kind) {
|
||||
case SyntaxKind.NullKeyword:
|
||||
case SyntaxKind.Identifier: // identifier includes undefined
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
if (isConvertableFunction(arg as FunctionLikeDeclaration, checker)) {
|
||||
visitedNestedConvertibleFunctions.set(getKeyFromNode(arg as FunctionLikeDeclaration), true);
|
||||
}
|
||||
/* falls through */
|
||||
case SyntaxKind.NullKeyword:
|
||||
case SyntaxKind.Identifier: // identifier includes undefined
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getKeyFromNode(exp: FunctionLikeDeclaration) {
|
||||
return `${exp.pos.toString()}:${exp.end.toString()}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -255,7 +255,7 @@ interface String { charAt: any; }
|
|||
interface Array<T> {}`
|
||||
};
|
||||
|
||||
function testConvertToAsyncFunction(caption: string, text: string, baselineFolder: string, includeLib?: boolean, expectFailure = false) {
|
||||
function testConvertToAsyncFunction(caption: string, text: string, baselineFolder: string, includeLib?: boolean, expectFailure = false, onlyProvideAction = false) {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection")!;
|
||||
if (!selectionRange) {
|
||||
|
@ -307,7 +307,7 @@ interface Array<T> {}`
|
|||
|
||||
const actions = codefix.getFixes(context);
|
||||
const action = find(actions, action => action.description === Diagnostics.Convert_to_async_function.message);
|
||||
if (expectFailure) {
|
||||
if (expectFailure && !onlyProvideAction) {
|
||||
assert.isNotTrue(action && action.changes.length > 0);
|
||||
return;
|
||||
}
|
||||
|
@ -1151,25 +1151,25 @@ function [#|f|]() {
|
|||
_testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpression", `
|
||||
const [#|foo|] = function () {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpressionWithName", `
|
||||
const foo = function [#|f|]() {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpressionAssignedToBindingPattern", `
|
||||
const { length } = [#|function|] () {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_catchBlockUniqueParams", `
|
||||
function [#|f|]() {
|
||||
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
|
||||
}
|
||||
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_bindingPattern", `
|
||||
|
@ -1178,7 +1178,7 @@ function [#|f|]() {
|
|||
}
|
||||
function res({ status, trailer }){
|
||||
console.log(status);
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_bindingPatternNameCollision", `
|
||||
|
@ -1188,7 +1188,7 @@ function [#|f|]() {
|
|||
}
|
||||
function res({ status, trailer }){
|
||||
console.log(status);
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_thenArgumentNotFunction", `
|
||||
|
@ -1209,7 +1209,7 @@ function [#|f|]() {
|
|||
}
|
||||
function res(result) {
|
||||
return Promise.resolve().then(x => console.log(result));
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromise", `
|
||||
|
@ -1241,7 +1241,7 @@ function [#|f|]() {
|
|||
return Promise.resolve(1)
|
||||
.then(x => Promise.reject(x))
|
||||
.catch(err => console.log(err));
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_nestedPromises", `
|
||||
|
@ -1266,6 +1266,22 @@ _testConvertToAsyncFunction("convertToAsyncFunction_exportModifier", `
|
|||
export function [#|foo|]() {
|
||||
return fetch('https://typescriptlang.org').then(s => console.log(s));
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_OutermostOnlySuccess", `
|
||||
function [#|foo|]() {
|
||||
return fetch('a').then(() => {
|
||||
return fetch('b').then(() => 'c');
|
||||
})
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunctionFailedSuggestion("convertToAsyncFunction_OutermostOnlyFailure", `
|
||||
function foo() {
|
||||
return fetch('a').then([#|() => {|]
|
||||
return fetch('b').then(() => 'c');
|
||||
})
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
|
@ -1276,4 +1292,8 @@ export function [#|foo|]() {
|
|||
function _testConvertToAsyncFunctionFailed(caption: string, text: string) {
|
||||
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", /*includeLib*/ true, /*expectFailure*/ true);
|
||||
}
|
||||
|
||||
function _testConvertToAsyncFunctionFailedSuggestion(caption: string, text: string) {
|
||||
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", /*includeLib*/ true, /*expectFailure*/ true, /*onlyProvideAction*/ true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// ==ORIGINAL==
|
||||
|
||||
function foo() {
|
||||
return fetch('a').then(/*[#|*/() => {/*|]*/
|
||||
return fetch('b').then(() => 'c');
|
||||
})
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
function foo() {
|
||||
return fetch('a').then(async () => {
|
||||
await fetch('b');
|
||||
return 'c';
|
||||
})
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// ==ORIGINAL==
|
||||
|
||||
function /*[#|*/foo/*|]*/() {
|
||||
return fetch('a').then(() => {
|
||||
return fetch('b').then(() => 'c');
|
||||
})
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
async function foo() {
|
||||
await fetch('a');
|
||||
await fetch('b');
|
||||
return 'c';
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// ==ORIGINAL==
|
||||
|
||||
function /*[#|*/foo/*|]*/() {
|
||||
return fetch('a').then(() => {
|
||||
return fetch('b').then(() => 'c');
|
||||
})
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
async function foo() {
|
||||
await fetch('a');
|
||||
await fetch('b');
|
||||
return 'c';
|
||||
}
|
|
@ -5,7 +5,7 @@ function /*[#|*/f/*|]*/() {
|
|||
}
|
||||
function res({ status, trailer }){
|
||||
console.log(status);
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
|
@ -15,4 +15,4 @@ async function f() {
|
|||
}
|
||||
function res({ status, trailer }){
|
||||
console.log(status);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ function /*[#|*/f/*|]*/() {
|
|||
}
|
||||
function res({ status, trailer }){
|
||||
console.log(status);
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
|
@ -15,4 +15,4 @@ async function f() {
|
|||
}
|
||||
function res({ status, trailer }){
|
||||
console.log(status);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ function /*[#|*/f/*|]*/() {
|
|||
}
|
||||
function res({ status, trailer }){
|
||||
console.log(status);
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
|
@ -17,4 +17,4 @@ async function f() {
|
|||
}
|
||||
function res({ status, trailer }){
|
||||
console.log(status);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ function /*[#|*/f/*|]*/() {
|
|||
}
|
||||
function res({ status, trailer }){
|
||||
console.log(status);
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
|
@ -17,4 +17,4 @@ async function f() {
|
|||
}
|
||||
function res({ status, trailer }){
|
||||
console.log(status);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ function /*[#|*/f/*|]*/() {
|
|||
return Promise.resolve(1)
|
||||
.then(x => Promise.reject(x))
|
||||
.catch(err => console.log(err));
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
|
@ -16,4 +16,4 @@ async function f() {
|
|||
catch (err) {
|
||||
return console.log(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ function /*[#|*/f/*|]*/() {
|
|||
return Promise.resolve(1)
|
||||
.then(x => Promise.reject(x))
|
||||
.catch(err => console.log(err));
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
|
@ -16,4 +16,4 @@ async function f() {
|
|||
catch (err) {
|
||||
return console.log(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// ==ORIGINAL==
|
||||
|
||||
function /*[#|*/f/*|]*/() {
|
||||
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
|
||||
}
|
||||
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
|
@ -15,5 +15,5 @@ async function f() {
|
|||
catch (x_1) {
|
||||
x_2 = "a";
|
||||
}
|
||||
return !!x_2;
|
||||
}
|
||||
return !!x_2;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// ==ORIGINAL==
|
||||
|
||||
function /*[#|*/f/*|]*/() {
|
||||
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
|
||||
}
|
||||
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
|
@ -15,5 +15,5 @@ async function f() {
|
|||
catch (x_1) {
|
||||
x_2 = "a";
|
||||
}
|
||||
return !!x_2;
|
||||
}
|
||||
return !!x_2;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ function /*[#|*/f/*|]*/() {
|
|||
}
|
||||
function res(result) {
|
||||
return Promise.resolve().then(x => console.log(result));
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
|
@ -16,4 +16,4 @@ async function f() {
|
|||
}
|
||||
function res(result) {
|
||||
return Promise.resolve().then(x => console.log(result));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ function /*[#|*/f/*|]*/() {
|
|||
}
|
||||
function res(result) {
|
||||
return Promise.resolve().then(x => console.log(result));
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
|
@ -16,4 +16,4 @@ async function f() {
|
|||
}
|
||||
function res(result) {
|
||||
return Promise.resolve().then(x => console.log(result));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
const /*[#|*/foo/*|]*/ = function () {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
const foo = async function () {
|
||||
const result = await fetch('https://typescriptlang.org');
|
||||
console.log(result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
const /*[#|*/foo/*|]*/ = function () {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
const foo = async function () {
|
||||
const result = await fetch('https://typescriptlang.org');
|
||||
console.log(result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
const { length } = /*[#|*/function/*|]*/ () {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
const { length } = async function () {
|
||||
const result = await fetch('https://typescriptlang.org');
|
||||
console.log(result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
const { length } = /*[#|*/function/*|]*/ () {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
const { length } = async function () {
|
||||
const result = await fetch('https://typescriptlang.org');
|
||||
console.log(result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
const foo = function /*[#|*/f/*|]*/() {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
const foo = async function f() {
|
||||
const result = await fetch('https://typescriptlang.org');
|
||||
console.log(result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
const foo = function /*[#|*/f/*|]*/() {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
const foo = async function f() {
|
||||
const result = await fetch('https://typescriptlang.org');
|
||||
console.log(result);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue