fix(isolated_declarations): Remove nested AssignmentPatterns from inside parameters (#4077)

The default values in destructured parameters are retained in
declarations, which can cause captured variables to be part of the emit
when they shouldn't be. This can also lead to unnecessary isolated
declaration errors when those variables are themselves missing type
annotations and can't be inferred.

For example:
```ts
const x = 42;
const y = '';
export function fooGood3({a = x, b: [{c = y}]}: object): void {}
```

before this change will be emitted as:
```ts
declare const x = 42;
declare const y = '';
export declare function fooGood3({ a = x, b: [{ c = y }] }: object): void;
```

and after this change will be emitted as:
```ts
export declare function fooGood3({ a, b: [{ c }] }: object): void;
```

Co-authored-by: MichaelMitchell-at <=>
This commit is contained in:
michaelm 2024-07-07 23:06:26 -04:00 committed by GitHub
parent 51eb8fe46c
commit 3fcad5e16f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 65 additions and 32 deletions

View file

@ -0,0 +1,24 @@
use oxc_ast::{
ast::BindingPatternKind, visit::walk_mut::walk_binding_pattern_kind, AstBuilder, VisitMut,
};
pub struct FormalParameterBindingPattern<'a> {
ast: AstBuilder<'a>,
}
impl<'a> VisitMut<'a> for FormalParameterBindingPattern<'a> {
fn visit_binding_pattern_kind(&mut self, kind: &mut BindingPatternKind<'a>) {
if let BindingPatternKind::AssignmentPattern(assignment) = kind {
*kind = self.ast.copy(&assignment.left.kind);
}
walk_binding_pattern_kind(self, kind);
}
}
impl<'a> FormalParameterBindingPattern<'a> {
pub fn remove_assignments_from_kind(ast: AstBuilder<'a>, kind: &mut BindingPatternKind<'a>) {
let mut visitor = FormalParameterBindingPattern { ast };
visitor.visit_binding_pattern_kind(kind);
}
}

View file

@ -9,6 +9,7 @@ use crate::{
function_must_have_explicit_return_type, implicitly_adding_undefined_to_type,
parameter_must_have_explicit_type,
},
formal_parameter_binding_pattern::FormalParameterBindingPattern,
IsolatedDeclarations,
};
@ -65,6 +66,8 @@ impl<'a> IsolatedDeclarations<'a> {
self.ast.copy(&param.pattern)
};
FormalParameterBindingPattern::remove_assignments_from_kind(self.ast, &mut pattern.kind);
if is_assignment_pattern || pattern.type_annotation.is_none() {
let type_annotation = pattern
.type_annotation

View file

@ -9,6 +9,7 @@ mod class;
mod declaration;
mod diagnostics;
mod r#enum;
mod formal_parameter_binding_pattern;
mod function;
mod inferrer;
mod literal;

View file

@ -10,6 +10,10 @@ export const fooGood2 = ({a, b}: object = { a: 1, b: 2 }): number => {
return 2;
}
const x = 42;
const y = '';
export function fooGood3({a = x, b: [{c = y}]}: object): void {}
// Incorrect
export function fnDeclBad<T>(p: T = [], rParam: T = "", r2: T): void { }
export function fnDeclBad2<T>(p: T = [], r2: T): void { }

View file

@ -8,6 +8,7 @@ export declare function fnDeclGood(p?: T, rParam?: string): void;
export declare function fnDeclGood2(p?: T, rParam?: number): void;
export declare function fooGood([a, b]?: any[]): number;
export declare const fooGood2: ({ a, b }?: object) => number;
export declare function fooGood3({ a, b: [{ c }] }: object): void;
export declare function fnDeclBad<T>(p: T, rParam: T, r2: T): void;
export declare function fnDeclBad2<T>(p: T, r2: T): void;
export declare function fnDeclBad3<T>(p: T, rParam?: T, r2: T): void;
@ -19,54 +20,54 @@ export declare const fooBad2: () => number;
x TS9025: Declaration emit for this parameter requires implicitly adding
| undefined to it's type. This is not supported with --isolatedDeclarations.
,-[14:30]
13 | // Incorrect
14 | export function fnDeclBad<T>(p: T = [], rParam: T = "", r2: T): void { }
,-[18:30]
17 | // Incorrect
18 | export function fnDeclBad<T>(p: T = [], rParam: T = "", r2: T): void { }
: ^^^^^^^^^
15 | export function fnDeclBad2<T>(p: T = [], r2: T): void { }
19 | export function fnDeclBad2<T>(p: T = [], r2: T): void { }
`----
x TS9025: Declaration emit for this parameter requires implicitly adding
| undefined to it's type. This is not supported with --isolatedDeclarations.
,-[14:41]
13 | // Incorrect
14 | export function fnDeclBad<T>(p: T = [], rParam: T = "", r2: T): void { }
,-[18:41]
17 | // Incorrect
18 | export function fnDeclBad<T>(p: T = [], rParam: T = "", r2: T): void { }
: ^^^^^^^^^^^^^^
15 | export function fnDeclBad2<T>(p: T = [], r2: T): void { }
19 | export function fnDeclBad2<T>(p: T = [], r2: T): void { }
`----
x TS9025: Declaration emit for this parameter requires implicitly adding
| undefined to it's type. This is not supported with --isolatedDeclarations.
,-[15:31]
14 | export function fnDeclBad<T>(p: T = [], rParam: T = "", r2: T): void { }
15 | export function fnDeclBad2<T>(p: T = [], r2: T): void { }
,-[19:31]
18 | export function fnDeclBad<T>(p: T = [], rParam: T = "", r2: T): void { }
19 | export function fnDeclBad2<T>(p: T = [], r2: T): void { }
: ^^^^^^^^^
16 | export function fnDeclBad3<T>(p: T = [], rParam?: T, r2: T): void { }
20 | export function fnDeclBad3<T>(p: T = [], rParam?: T, r2: T): void { }
`----
x TS9025: Declaration emit for this parameter requires implicitly adding
| undefined to it's type. This is not supported with --isolatedDeclarations.
,-[16:31]
15 | export function fnDeclBad2<T>(p: T = [], r2: T): void { }
16 | export function fnDeclBad3<T>(p: T = [], rParam?: T, r2: T): void { }
,-[20:31]
19 | export function fnDeclBad2<T>(p: T = [], r2: T): void { }
20 | export function fnDeclBad3<T>(p: T = [], rParam?: T, r2: T): void { }
: ^^^^^^^^^
17 |
`----
x TS9011: Parameter must have an explicit type annotation with
| --isolatedDeclarations.
,-[18:24]
17 |
18 | export function fooBad([a, b] = [1, 2]): number {
: ^^^^^^^^^^^^^^^
19 | return 2;
`----
x TS9011: Parameter must have an explicit type annotation with
| --isolatedDeclarations.
,-[22:25]
21 |
22 | export const fooBad2 = ({a, b} = { a: 1, b: 2 }): number => {
: ^^^^^^^^^^^^^^^^^^^^^^^
`----
x TS9011: Parameter must have an explicit type annotation with
| --isolatedDeclarations.
,-[22:24]
21 |
22 | export function fooBad([a, b] = [1, 2]): number {
: ^^^^^^^^^^^^^^^
23 | return 2;
`----
x TS9011: Parameter must have an explicit type annotation with
| --isolatedDeclarations.
,-[26:25]
25 |
26 | export const fooBad2 = ({a, b} = { a: 1, b: 2 }): number => {
: ^^^^^^^^^^^^^^^^^^^^^^^
27 | return 2;
`----