KEMBAR78
add support to convert lambda to function and vice-versa by D0nGiovanni · Pull Request #28250 · microsoft/TypeScript · GitHub
Skip to content

Conversation

@D0nGiovanni
Copy link
Contributor

Fixes #23299

@msftclas
Copy link

msftclas commented Oct 31, 2018

CLA assistant check
All CLA requirements met.

@sandersn sandersn requested review from a user, DanielRosenwasser and sandersn October 31, 2018 14:32
Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to extend this to allow arbitrary function expressions to be converted to arrow functions, as long as their name (if it exists) isn't used. You can use FindAllReferences.isSymbolReferencedInFile to determine whether the name is used.


function getFunctionInfo(file: SourceFile, startPosition: number): FunctionInfo | undefined {
const token = getTokenAtPosition(file, startPosition);
let maybeFunc;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could just be two different variables, one for each time it's assigned to.

let maybeFunc;

maybeFunc = getArrowFunctionFromVariableDeclaration(token.parent);
if (!!maybeFunc) return { selectedVariableDeclaration: true, func: maybeFunc };
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to have !! for the condition of an if, it automatically booleanifies everything.

return getEditInfoForConvertToArrowFunction(context, func);

default:
Debug.fail("invalid action");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just return Debug.fail("Invalid action"); since it returns never.


function getEditInfoForConvertToArrowFunction(context: RefactorContext, func: FunctionExpression | ArrowFunction): RefactorEditInfo | undefined {
const { file } = context;
if (!isFunctionExpression(func)) return undefined;
Copy link

@ghost ghost Nov 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter type should just be FunctionExpression then?

}

function canBeConvertedToExpression(body: Block, head: Statement): head is ReturnStatement | ExpressionStatement {
return body.statements.length === 1 && ((isReturnStatement(head) && !!head.expression) || isExpressionStatement(head));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about the last condition there. () => foo() has a different type from () => { foo(); }.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right.
to clarify

let epsilon = () => "epsilon";
let foo = () => epsilon()       // foo: () => string
let bar = () => { epsilon() }   // bar: () => void

body = func.body;
}

const newNode = createArrowFunction(func.modifiers, func.typeParameters, func.parameters, func.type, /* equalsGreaterThanToken */ undefined, body);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suprised this works without the token -- seems like it would be better to createToken(SyntaxKind.EqualsGreaterThanToken) even if the emitter doesn't currently require it.

const body = convertToBlock(func.body);
const newNode = createFunctionExpression(func.modifiers, func.asteriskToken, /* name */ undefined, func.typeParameters, func.parameters, func.type, body);
const edits = textChanges.ChangeTracker.with(context, t => t.replaceNode(file, func, newNode));
return { renameFilename: undefined, renameLocation: undefined, edits };
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be better for these functions to just return the edits, and some outer function to wrap them in RefactorEditInfo.

@@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />

//// let foo = /*x*/(/*y*/) => 1 + 1;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be tests where the function expression isn't preceded by a variable declaration.

@ghost ghost mentioned this pull request Nov 13, 2018
@bigaru
Copy link
Contributor

bigaru commented Jan 23, 2019

Hi @Andy-MS
A friend pointed out that this behaves differently in function than in lambda.

I've solved that using forEachChild to detect whether a body contains a this. I find my solution suboptimal because if the body is large, then it will also take time to detect this. However, the computation for getAvailableActions should be quick.

Are the any auxiliary function which can provide a better way to solve this?

@ghost
Copy link

ghost commented Jan 23, 2019

@bigaru Make sure you're not testing any nested functions or classes, which would come with their own meaning of this anyway. If you're not descending into inner functions then I would expect forEachChild wouldn't be too slow.
CC @sandersn @DanielRosenwasser for review

@jessetrinity
Copy link
Contributor

@D0nGiovanni if you are still interested in this PR I would like to get it in once the merge conflicts are resolved. Thanks!

@D0nGiovanni
Copy link
Contributor Author

@jessetrinity Alright! I should have it done by the end of the weekend.

@bigaru
Copy link
Contributor

bigaru commented May 27, 2020

When @D0nGiovanni told me, I was so excited that I resolved the conflicts.

Thanks @jessetrinity for your effort!

@jessetrinity jessetrinity merged commit 1d1c167 into microsoft:master Jun 1, 2020
@jessetrinity
Copy link
Contributor

@D0nGiovanni @bigaru thank you for the contribution to TypeScript!

@microsoft microsoft locked as resolved and limited conversation to collaborators Oct 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

For Backlog Bug PRs that fix a backlog bug

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

CodeAction: convert lambda expression declaration to function

6 participants