Don't capture type parameters defined inside the extraction range with "Extract to function" (#53543)

This commit is contained in:
Maria José Solano
2023-03-27 18:12:41 -07:00
committed by GitHub
parent 85ef01d31a
commit 6e44db7d1d
3 changed files with 47 additions and 4 deletions

View File

@@ -111,6 +111,7 @@ import {
LabeledStatement,
last,
map,
mapDefined,
MethodDeclaration,
Modifier,
ModifierFlags,
@@ -1070,12 +1071,12 @@ function extractFunctionInScope(
callArguments.push(factory.createIdentifier(name));
});
const typeParametersAndDeclarations = arrayFrom(typeParameterUsages.values(), type => ({ type, declaration: getFirstDeclaration(type) }));
const typeParametersAndDeclarations = arrayFrom(typeParameterUsages.values(), type => ({ type, declaration: getFirstDeclarationBeforePosition(type, context.startPosition) }));
const sortedTypeParametersAndDeclarations = typeParametersAndDeclarations.sort(compareTypesByDeclarationOrder);
const typeParameters: readonly TypeParameterDeclaration[] | undefined = sortedTypeParametersAndDeclarations.length === 0
? undefined
: sortedTypeParametersAndDeclarations.map(t => t.declaration as TypeParameterDeclaration);
: mapDefined(sortedTypeParametersAndDeclarations, ({ declaration }) => declaration as TypeParameterDeclaration);
// Strictly speaking, we should check whether each name actually binds to the appropriate type
// parameter. In cases of shadowing, they may not.
@@ -1547,13 +1548,13 @@ function getContainingVariableDeclarationIfInList(node: Node, scope: Scope) {
}
}
function getFirstDeclaration(type: Type): Declaration | undefined {
function getFirstDeclarationBeforePosition(type: Type, position: number): Declaration | undefined {
let firstDeclaration;
const symbol = type.symbol;
if (symbol && symbol.declarations) {
for (const declaration of symbol.declarations) {
if (firstDeclaration === undefined || declaration.pos < firstDeclaration.pos) {
if ((firstDeclaration === undefined || declaration.pos < firstDeclaration.pos) && declaration.pos < position) {
firstDeclaration = declaration;
}
}

View File

@@ -0,0 +1,22 @@
/// <reference path='fourslash.ts' />
////function f() {
//// let g = /*start*/<T>(x: T) => x/*end*/;
//// return g;
////}
goTo.select('start', 'end');
edit.applyRefactor({
refactorName: "Extract Symbol",
actionName: "function_scope_1",
actionDescription: "Extract to function in global scope",
newContent:
`function f() {
let g = /*RENAME*/newFunction();
return g;
}
function newFunction() {
return <T>(x: T) => x;
}
`});

View File

@@ -0,0 +1,20 @@
/// <reference path='fourslash.ts' />
////function satisfies<A>() {
//// return /*start*/<T extends A>(x: T) => x/*end*/;
////}
goTo.select('start', 'end');
edit.applyRefactor({
refactorName: "Extract Symbol",
actionName: "function_scope_1",
actionDescription: "Extract to function in global scope",
newContent:
`function satisfies<A>() {
return /*RENAME*/newFunction<A>();
}
function newFunction<A>() {
return <T extends A>(x: T) => x;
}
`});