diff --git a/.changeset/ts2371-declare-object-defaults.md b/.changeset/ts2371-declare-object-defaults.md new file mode 100644 index 000000000000..01853b3c8a32 --- /dev/null +++ b/.changeset/ts2371-declare-object-defaults.md @@ -0,0 +1,6 @@ +--- +swc_core: patch +swc_ecma_parser: patch +--- + +fix(es/parser): emit TS2371 for object-pattern defaults in declare signatures diff --git a/crates/swc_ecma_parser/src/parser/class_and_fn.rs b/crates/swc_ecma_parser/src/parser/class_and_fn.rs index bb4915dc7b44..0f3f3225ef71 100644 --- a/crates/swc_ecma_parser/src/parser/class_and_fn.rs +++ b/crates/swc_ecma_parser/src/parser/class_and_fn.rs @@ -355,16 +355,7 @@ impl Parser { if p.syntax().typescript() && body.is_none() { // Declare functions cannot have assignment pattern in parameters for param in ¶ms { - // TODO: Search deeply for assignment pattern using a Visitor - - let span = match ¶m.pat { - Pat::Assign(ref p) => Some(p.span()), - _ => None, - }; - - if let Some(span) = span { - p.emit_err(span, SyntaxError::TS2371) - } + p.emit_ts2371_for_param_initializers(¶m.pat); } } @@ -1249,22 +1240,17 @@ impl Parser { if self.syntax().typescript() && body.is_none() { // Declare constructors cannot have assignment pattern in parameters for param in ¶ms { - // TODO: Search deeply for assignment pattern using a Visitor - - let span = match *param { - ParamOrTsParamProp::Param(ref param) => match param.pat { - Pat::Assign(ref p) => Some(p.span()), - _ => None, - }, + match param { + ParamOrTsParamProp::Param(param) => { + self.emit_ts2371_for_param_initializers(¶m.pat); + } ParamOrTsParamProp::TsParamProp(TsParamProp { - param: TsParamPropParam::Assign(ref p), + param: TsParamPropParam::Assign(p), .. - }) => Some(p.span()), - _ => None, - }; - - if let Some(span) = span { - self.emit_err(span, SyntaxError::TS2371) + }) => { + self.emit_err(p.span(), SyntaxError::TS2371); + } + _ => {} } } } diff --git a/crates/swc_ecma_parser/src/parser/object.rs b/crates/swc_ecma_parser/src/parser/object.rs index d58aa4528eb7..2adb90eafc16 100644 --- a/crates/swc_ecma_parser/src/parser/object.rs +++ b/crates/swc_ecma_parser/src/parser/object.rs @@ -75,6 +75,10 @@ impl Parser { }; let value = if self.input_mut().eat(Token::Eq) { + // Do not emit TS2371 here: `Context::InDeclare` also covers ambient + // variable bindings such as `declare const { a = 1 }`, which TypeScript + // accepts. Declare function/constructor parameters are rejected by + // `emit_ts2371_for_param_initializers` after the signature is parsed. self.allow_in_expr(Self::parse_assignment_expr).map(Some)? } else { let ctx = self.ctx(); diff --git a/crates/swc_ecma_parser/src/parser/pat.rs b/crates/swc_ecma_parser/src/parser/pat.rs index 503faa7871af..acc341d96e34 100644 --- a/crates/swc_ecma_parser/src/parser/pat.rs +++ b/crates/swc_ecma_parser/src/parser/pat.rs @@ -77,6 +77,49 @@ impl Parser { } } + /// Emit TS2371 for any parameter initializer nested in a binding pattern. + /// + /// Used for ambient / declare function and constructor signatures where + /// top-level AssignPat checks alone miss object shorthand defaults and + /// nested defaults. + pub(crate) fn emit_ts2371_for_param_initializers(&mut self, pat: &Pat) { + match pat { + Pat::Assign(a) => { + self.emit_err(a.span(), SyntaxError::TS2371); + self.emit_ts2371_for_param_initializers(&a.left); + } + Pat::Array(arr) => { + for elem in arr.elems.iter().flatten() { + self.emit_ts2371_for_param_initializers(elem); + } + } + Pat::Object(obj) => { + for prop in &obj.props { + match prop { + ObjectPatProp::KeyValue(KeyValuePatProp { value, .. }) + | ObjectPatProp::Rest(RestPat { arg: value, .. }) => { + self.emit_ts2371_for_param_initializers(value); + } + ObjectPatProp::Assign(AssignPatProp { + span, + value: Some(_), + .. + }) => { + self.emit_err(*span, SyntaxError::TS2371); + } + ObjectPatProp::Assign(AssignPatProp { value: None, .. }) => {} + #[cfg(swc_ast_unknown)] + _ => {} + } + } + } + Pat::Rest(r) => self.emit_ts2371_for_param_initializers(&r.arg), + Pat::Ident(_) | Pat::Invalid(_) | Pat::Expr(_) => {} + #[cfg(swc_ast_unknown)] + _ => {} + } + } + fn assign_pat_type_ann(&mut self, pat: &mut Pat, span: Span, type_ann: Box) { let type_ann = Some(Box::new(TsTypeAnn { span, type_ann })); @@ -463,9 +506,10 @@ impl Parser { self.emit_err(right.span(), SyntaxError::AwaitParamInAsync); } - if self.ctx().contains(Context::InDeclare) { - self.emit_err(self.span(start), SyntaxError::TS2371); - } + // Do not emit TS2371 here. Ambient destructuring such as + // `declare const { a: b = 1 }` is valid, and declare / type-signature + // parameters are checked by `emit_ts2371_for_param_initializers` + // after the parameter list is parsed (avoids duplicate diagnostics). return Ok(AssignPat { span: self.span(start), @@ -654,9 +698,8 @@ impl Parser { { self.emit_err(right.span(), SyntaxError::AwaitParamInAsync); } - if self.ctx().contains(Context::InDeclare) { - self.emit_err(self.span(start), SyntaxError::TS2371); - } + // TS2371 for declare / signature parameters is emitted by + // `emit_ts2371_for_param_initializers` after the list is parsed. AssignPat { span: self.span(start), diff --git a/crates/swc_ecma_parser/src/parser/tests.rs b/crates/swc_ecma_parser/src/parser/tests.rs index c984d9c41a05..06ce8e1be82d 100644 --- a/crates/swc_ecma_parser/src/parser/tests.rs +++ b/crates/swc_ecma_parser/src/parser/tests.rs @@ -36,6 +36,25 @@ fn assert_module_error(src: &'static str) -> Module { }) } +#[test] +fn ts2371_declare_params_are_not_duplicated() { + // Eager parse-time TS2371 plus the post-list walker must not double-report. + test_parser( + "declare function top(a = 1): void; declare function obj({ a = 1 }): void;", + Syntax::Typescript(Default::default()), + |p| { + let _ = p.parse_typescript_module()?; + let errors = p.take_errors(); + let n = errors + .iter() + .filter(|e| matches!(e.kind(), crate::error::SyntaxError::TS2371)) + .count(); + assert_eq!(n, 2, "{errors:?}"); + Ok(()) + }, + ); +} + #[test] fn parse_program_module_01() { module("import 'foo';"); diff --git a/crates/swc_ecma_parser/src/parser/typescript.rs b/crates/swc_ecma_parser/src/parser/typescript.rs index 4b1d4de9627d..2573b24bee3a 100644 --- a/crates/swc_ecma_parser/src/parser/typescript.rs +++ b/crates/swc_ecma_parser/src/parser/typescript.rs @@ -2629,6 +2629,12 @@ impl Parser { Pat::Array(pat) => TsFnParam::Array(pat), Pat::Object(pat) => TsFnParam::Object(pat), Pat::Rest(pat) => TsFnParam::Rest(pat), + // Parameter initializers are illegal in type / call signatures + // (TS2371). Recover by keeping the binding and reporting once. + Pat::Assign(a) => { + p.emit_err(a.span(), SyntaxError::TS2371); + return pat_to_ts_fn_param(p, *a.left); + } _ => unexpected!( p, "an identifier, [ for an array pattern, { for an object patter or ... for a \ @@ -2718,6 +2724,9 @@ impl Parser { } expect!(self, Token::RParen); + for param in &list { + self.emit_ts2371_for_ts_fn_param(param); + } return Ok(list); } @@ -2728,9 +2737,51 @@ impl Parser { list.push(pat_to_ts_fn_param(self, param.pat)?); } expect!(self, Token::RParen); + // Nested object/array defaults in type positions never go through + // `parse_fn_args_body`'s post-walk; check them here. + for param in &list { + self.emit_ts2371_for_ts_fn_param(param); + } Ok(list) } + /// Emit TS2371 for initializers nested in a type/call/method signature + /// parameter. Top-level `AssignPat` is already reported while converting to + /// [`TsFnParam`]; this covers object shorthand / nested defaults. + fn emit_ts2371_for_ts_fn_param(&mut self, param: &TsFnParam) { + match param { + TsFnParam::Ident(_) => {} + TsFnParam::Array(arr) => { + for elem in arr.elems.iter().flatten() { + self.emit_ts2371_for_param_initializers(elem); + } + } + TsFnParam::Object(obj) => { + for prop in &obj.props { + match prop { + ObjectPatProp::KeyValue(KeyValuePatProp { value, .. }) + | ObjectPatProp::Rest(RestPat { arg: value, .. }) => { + self.emit_ts2371_for_param_initializers(value); + } + ObjectPatProp::Assign(AssignPatProp { + span, + value: Some(_), + .. + }) => { + self.emit_err(*span, SyntaxError::TS2371); + } + ObjectPatProp::Assign(AssignPatProp { value: None, .. }) => {} + #[cfg(swc_ast_unknown)] + _ => {} + } + } + } + TsFnParam::Rest(r) => self.emit_ts2371_for_param_initializers(&r.arg), + #[cfg(swc_ast_unknown)] + _ => {} + } + } + /// `tsIsStartOfMappedType` fn is_ts_start_of_mapped_type(&mut self) -> bool { debug_assert!(self.input().syntax().typescript()); diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/array-still-errors/input.ts b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/array-still-errors/input.ts new file mode 100644 index 000000000000..2790651c622d --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/array-still-errors/input.ts @@ -0,0 +1,2 @@ +declare function bar([x = 1]: number[]): void; +declare function baz([x, y = 2]: number[]): void; diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/array-still-errors/input.ts.swc-stderr b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/array-still-errors/input.ts.swc-stderr new file mode 100644 index 000000000000..f01a8abcd6ba --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/array-still-errors/input.ts.swc-stderr @@ -0,0 +1,12 @@ + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/array-still-errors/input.ts:1:1] + 1 | declare function bar([x = 1]: number[]): void; + : ^^^^^ + 2 | declare function baz([x, y = 2]: number[]): void; + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/array-still-errors/input.ts:2:1] + 1 | declare function bar([x = 1]: number[]): void; + 2 | declare function baz([x, y = 2]: number[]): void; + : ^^^^^ + `---- diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/declare-method/input.ts b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/declare-method/input.ts new file mode 100644 index 000000000000..2f672281267e --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/declare-method/input.ts @@ -0,0 +1,4 @@ +declare class C { + method({ a = 1 }: { a?: number }): void; + constructor({ a = 1 }: { a?: number }); +} diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/declare-method/input.ts.swc-stderr b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/declare-method/input.ts.swc-stderr new file mode 100644 index 000000000000..7a8c7130d53a --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/declare-method/input.ts.swc-stderr @@ -0,0 +1,14 @@ + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/declare-method/input.ts:2:1] + 1 | declare class C { + 2 | method({ a = 1 }: { a?: number }): void; + : ^^^^^ + 3 | constructor({ a = 1 }: { a?: number }); + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/declare-method/input.ts:3:1] + 2 | method({ a = 1 }: { a?: number }): void; + 3 | constructor({ a = 1 }: { a?: number }); + : ^^^^^ + 4 | } + `---- diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/key-value-default/input.ts b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/key-value-default/input.ts new file mode 100644 index 000000000000..897733c329f2 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/key-value-default/input.ts @@ -0,0 +1 @@ +declare function foo({ a: b = 1 }: { a?: number }): void; diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/key-value-default/input.ts.swc-stderr b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/key-value-default/input.ts.swc-stderr new file mode 100644 index 000000000000..6bcc9627e55a --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/key-value-default/input.ts.swc-stderr @@ -0,0 +1,5 @@ + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/key-value-default/input.ts:1:1] + 1 | declare function foo({ a: b = 1 }: { a?: number }): void; + : ^^^^^ + `---- diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/mixed/input.ts b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/mixed/input.ts new file mode 100644 index 000000000000..e393757a821f --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/mixed/input.ts @@ -0,0 +1,4 @@ +declare function top(a = 1): void; +declare function obj({ a = 1 }): void; +declare function arr([a = 1]): void; +declare function nested({ a: { b = 1 } }): void; diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/mixed/input.ts.swc-stderr b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/mixed/input.ts.swc-stderr new file mode 100644 index 000000000000..8e77536c2977 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/mixed/input.ts.swc-stderr @@ -0,0 +1,26 @@ + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/mixed/input.ts:1:1] + 1 | declare function top(a = 1): void; + : ^^^^^ + 2 | declare function obj({ a = 1 }): void; + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/mixed/input.ts:2:1] + 1 | declare function top(a = 1): void; + 2 | declare function obj({ a = 1 }): void; + : ^^^^^ + 3 | declare function arr([a = 1]): void; + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/mixed/input.ts:3:1] + 2 | declare function obj({ a = 1 }): void; + 3 | declare function arr([a = 1]): void; + : ^^^^^ + 4 | declare function nested({ a: { b = 1 } }): void; + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/mixed/input.ts:4:1] + 3 | declare function arr([a = 1]): void; + 4 | declare function nested({ a: { b = 1 } }): void; + : ^^^^^ + `---- diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/nested-object/input.ts b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/nested-object/input.ts new file mode 100644 index 000000000000..0fce24c9d691 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/nested-object/input.ts @@ -0,0 +1,2 @@ +declare function foo({ a: { b = 1 } }: { a: { b?: number } }): void; +declare function bar({ a: [x = 1] }: { a: number[] }): void; diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/nested-object/input.ts.swc-stderr b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/nested-object/input.ts.swc-stderr new file mode 100644 index 000000000000..5ea8be5278a9 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/nested-object/input.ts.swc-stderr @@ -0,0 +1,12 @@ + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/nested-object/input.ts:1:1] + 1 | declare function foo({ a: { b = 1 } }: { a: { b?: number } }): void; + : ^^^^^ + 2 | declare function bar({ a: [x = 1] }: { a: number[] }): void; + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/nested-object/input.ts:2:1] + 1 | declare function foo({ a: { b = 1 } }: { a: { b?: number } }): void; + 2 | declare function bar({ a: [x = 1] }: { a: number[] }): void; + : ^^^^^ + `---- diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/object-shorthand/input.ts b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/object-shorthand/input.ts new file mode 100644 index 000000000000..e83cfc629b38 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/object-shorthand/input.ts @@ -0,0 +1,2 @@ +declare function foo({ a = 1 }: { a?: number }): void; +declare function bar({ a = 1, b = 2 }: { a?: number; b?: number }): void; diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/object-shorthand/input.ts.swc-stderr b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/object-shorthand/input.ts.swc-stderr new file mode 100644 index 000000000000..ee62c001ec53 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/object-shorthand/input.ts.swc-stderr @@ -0,0 +1,18 @@ + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/object-shorthand/input.ts:1:1] + 1 | declare function foo({ a = 1 }: { a?: number }): void; + : ^^^^^ + 2 | declare function bar({ a = 1, b = 2 }: { a?: number; b?: number }): void; + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/object-shorthand/input.ts:2:1] + 1 | declare function foo({ a = 1 }: { a?: number }): void; + 2 | declare function bar({ a = 1, b = 2 }: { a?: number; b?: number }): void; + : ^^^^^ + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/object-shorthand/input.ts:2:1] + 1 | declare function foo({ a = 1 }: { a?: number }): void; + 2 | declare function bar({ a = 1, b = 2 }: { a?: number; b?: number }): void; + : ^^^^^ + `---- diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/type-signature/input.ts b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/type-signature/input.ts new file mode 100644 index 000000000000..d169616638b0 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/type-signature/input.ts @@ -0,0 +1,8 @@ +type T1 = (a = 1) => void; +type T2 = ({ a = 1 }: { a?: number }) => void; +type T3 = ({ a: b = 1 }: { a?: number }) => void; +interface I { + (x = 1): void; + ({ a = 1 }: { a?: number }): void; + method({ a = 1 }: { a?: number }): void; +} diff --git a/crates/swc_ecma_parser/tests/typescript-errors/ts2371/type-signature/input.ts.swc-stderr b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/type-signature/input.ts.swc-stderr new file mode 100644 index 000000000000..7dcef951199e --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript-errors/ts2371/type-signature/input.ts.swc-stderr @@ -0,0 +1,41 @@ + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/type-signature/input.ts:1:1] + 1 | type T1 = (a = 1) => void; + : ^^^^^ + 2 | type T2 = ({ a = 1 }: { a?: number }) => void; + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/type-signature/input.ts:2:1] + 1 | type T1 = (a = 1) => void; + 2 | type T2 = ({ a = 1 }: { a?: number }) => void; + : ^^^^^ + 3 | type T3 = ({ a: b = 1 }: { a?: number }) => void; + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/type-signature/input.ts:3:1] + 2 | type T2 = ({ a = 1 }: { a?: number }) => void; + 3 | type T3 = ({ a: b = 1 }: { a?: number }) => void; + : ^^^^^ + 4 | interface I { + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/type-signature/input.ts:5:1] + 4 | interface I { + 5 | (x = 1): void; + : ^^^^^ + 6 | ({ a = 1 }: { a?: number }): void; + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/type-signature/input.ts:6:1] + 5 | (x = 1): void; + 6 | ({ a = 1 }: { a?: number }): void; + : ^^^^^ + 7 | method({ a = 1 }: { a?: number }): void; + `---- + x A parameter initializer is only allowed in a function or constructor implementation + ,-[$DIR/tests/typescript-errors/ts2371/type-signature/input.ts:7:1] + 6 | ({ a = 1 }: { a?: number }): void; + 7 | method({ a = 1 }: { a?: number }): void; + : ^^^^^ + 8 | } + `---- diff --git a/crates/swc_ecma_parser/tests/typescript/ts2371-declare-const-ok/input.ts b/crates/swc_ecma_parser/tests/typescript/ts2371-declare-const-ok/input.ts new file mode 100644 index 000000000000..52866e48bf46 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript/ts2371-declare-const-ok/input.ts @@ -0,0 +1,2 @@ +declare const { a = 1 }: { a?: number }; +declare const { a: b = 1 }: { a?: number }; diff --git a/crates/swc_ecma_parser/tests/typescript/ts2371-declare-const-ok/input.ts.json b/crates/swc_ecma_parser/tests/typescript/ts2371-declare-const-ok/input.ts.json new file mode 100644 index 000000000000..3d6cc6bf4d73 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript/ts2371-declare-const-ok/input.ts.json @@ -0,0 +1,239 @@ +{ + "type": "Script", + "span": { + "start": 1, + "end": 85 + }, + "body": [ + { + "type": "VariableDeclaration", + "span": { + "start": 1, + "end": 41 + }, + "ctxt": 0, + "kind": "const", + "declare": true, + "declarations": [ + { + "type": "VariableDeclarator", + "span": { + "start": 15, + "end": 40 + }, + "id": { + "type": "ObjectPattern", + "span": { + "start": 15, + "end": 24 + }, + "properties": [ + { + "type": "AssignmentPatternProperty", + "span": { + "start": 17, + "end": 22 + }, + "key": { + "type": "Identifier", + "span": { + "start": 17, + "end": 18 + }, + "ctxt": 0, + "value": "a", + "optional": false, + "typeAnnotation": null + }, + "value": { + "type": "NumericLiteral", + "span": { + "start": 21, + "end": 22 + }, + "value": 1.0, + "raw": "1" + } + } + ], + "optional": false, + "typeAnnotation": { + "type": "TsTypeAnnotation", + "span": { + "start": 24, + "end": 40 + }, + "typeAnnotation": { + "type": "TsTypeLiteral", + "span": { + "start": 26, + "end": 40 + }, + "members": [ + { + "type": "TsPropertySignature", + "span": { + "start": 28, + "end": 38 + }, + "readonly": false, + "key": { + "type": "Identifier", + "span": { + "start": 28, + "end": 29 + }, + "ctxt": 0, + "value": "a", + "optional": false + }, + "computed": false, + "optional": true, + "typeAnnotation": { + "type": "TsTypeAnnotation", + "span": { + "start": 30, + "end": 38 + }, + "typeAnnotation": { + "type": "TsKeywordType", + "span": { + "start": 32, + "end": 38 + }, + "kind": "number" + } + } + } + ] + } + } + }, + "init": null, + "definite": false + } + ] + }, + { + "type": "VariableDeclaration", + "span": { + "start": 42, + "end": 85 + }, + "ctxt": 0, + "kind": "const", + "declare": true, + "declarations": [ + { + "type": "VariableDeclarator", + "span": { + "start": 56, + "end": 84 + }, + "id": { + "type": "ObjectPattern", + "span": { + "start": 56, + "end": 68 + }, + "properties": [ + { + "type": "KeyValuePatternProperty", + "key": { + "type": "Identifier", + "span": { + "start": 58, + "end": 59 + }, + "value": "a" + }, + "value": { + "type": "AssignmentPattern", + "span": { + "start": 61, + "end": 66 + }, + "left": { + "type": "Identifier", + "span": { + "start": 61, + "end": 62 + }, + "ctxt": 0, + "value": "b", + "optional": false, + "typeAnnotation": null + }, + "right": { + "type": "NumericLiteral", + "span": { + "start": 65, + "end": 66 + }, + "value": 1.0, + "raw": "1" + } + } + } + ], + "optional": false, + "typeAnnotation": { + "type": "TsTypeAnnotation", + "span": { + "start": 68, + "end": 84 + }, + "typeAnnotation": { + "type": "TsTypeLiteral", + "span": { + "start": 70, + "end": 84 + }, + "members": [ + { + "type": "TsPropertySignature", + "span": { + "start": 72, + "end": 82 + }, + "readonly": false, + "key": { + "type": "Identifier", + "span": { + "start": 72, + "end": 73 + }, + "ctxt": 0, + "value": "a", + "optional": false + }, + "computed": false, + "optional": true, + "typeAnnotation": { + "type": "TsTypeAnnotation", + "span": { + "start": 74, + "end": 82 + }, + "typeAnnotation": { + "type": "TsKeywordType", + "span": { + "start": 76, + "end": 82 + }, + "kind": "number" + } + } + } + ] + } + } + }, + "init": null, + "definite": false + } + ] + } + ], + "interpreter": null +}