swc_ecma_lexer/common/parser/
typescript.rs

1use std::fmt::Write;
2
3use either::Either;
4use swc_atoms::{atom, Atom};
5use swc_common::{BytePos, Span, Spanned};
6use swc_ecma_ast::*;
7
8use super::{
9    class_and_fn::{parse_class_decl, parse_fn_block_or_expr_body, parse_fn_decl},
10    eof_error,
11    expr::{is_start_of_left_hand_side_expr, parse_new_expr},
12    ident::parse_maybe_private_name,
13    is_simple_param_list::IsSimpleParameterList,
14    make_decl_declare,
15    stmt::parse_var_stmt,
16    PResult, Parser,
17};
18use crate::{
19    common::{
20        context::Context,
21        lexer::token::TokenFactory,
22        parser::{
23            buffer::Buffer,
24            expr::{parse_assignment_expr, parse_lit, parse_str_lit, parse_subscripts},
25            ident::{parse_ident, parse_ident_name},
26            module_item::parse_module_item_block_body,
27            object::parse_object_expr,
28            pat::{parse_binding_pat_or_ident, parse_formal_params},
29        },
30    },
31    error::SyntaxError,
32};
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum ParsingContext {
36    EnumMembers,
37    HeritageClauseElement,
38    TupleElementTypes,
39    TypeMembers,
40    TypeParametersOrArguments,
41}
42
43#[derive(Clone, Copy, PartialEq, Eq)]
44enum UnionOrIntersection {
45    Union,
46    Intersection,
47}
48
49#[derive(Clone, Copy, PartialEq, Eq)]
50enum SignatureParsingMode {
51    TSCallSignatureDeclaration,
52    TSConstructSignatureDeclaration,
53}
54
55/// `tsParseList`
56fn parse_ts_list<'a, P: Parser<'a>, T, F>(
57    p: &mut P,
58    kind: ParsingContext,
59    mut parse_element: F,
60) -> PResult<Vec<T>>
61where
62    F: FnMut(&mut P) -> PResult<T>,
63{
64    debug_assert!(p.input().syntax().typescript());
65    let mut buf = Vec::with_capacity(8);
66    while !is_ts_list_terminator(p, kind) {
67        // Skipping "parseListElement" from the TS source since that's just for error
68        // handling.
69        buf.push(parse_element(p)?);
70    }
71    Ok(buf)
72}
73
74/// `tsTryParse`
75pub(super) fn try_parse_ts_bool<'a, P: Parser<'a>, F>(p: &mut P, op: F) -> PResult<bool>
76where
77    F: FnOnce(&mut P) -> PResult<Option<bool>>,
78{
79    if !p.input().syntax().typescript() {
80        return Ok(false);
81    }
82
83    let prev_ignore_error = p.input().get_ctx().contains(Context::IgnoreError);
84    let checkpoint = p.checkpoint_save();
85    p.set_ctx(p.ctx() | Context::IgnoreError);
86    let res = op(p);
87    match res {
88        Ok(Some(res)) if res => {
89            let mut ctx = p.ctx();
90            ctx.set(Context::IgnoreError, prev_ignore_error);
91            p.input_mut().set_ctx(ctx);
92            Ok(res)
93        }
94        _ => {
95            p.checkpoint_load(checkpoint);
96            Ok(false)
97        }
98    }
99}
100
101/// `tsParseDelimitedList`
102fn parse_ts_delimited_list_inner<'a, P: Parser<'a>, T, F>(
103    p: &mut P,
104    kind: ParsingContext,
105    mut parse_element: F,
106) -> PResult<Vec<T>>
107where
108    F: FnMut(&mut P) -> PResult<(BytePos, T)>,
109{
110    debug_assert!(p.input().syntax().typescript());
111    let mut buf = Vec::new();
112    loop {
113        trace_cur!(p, parse_ts_delimited_list_inner__element);
114
115        if is_ts_list_terminator(p, kind) {
116            break;
117        }
118
119        let (_, element) = parse_element(p)?;
120        buf.push(element);
121
122        if p.input_mut().eat(&P::Token::COMMA) {
123            continue;
124        }
125
126        if is_ts_list_terminator(p, kind) {
127            break;
128        }
129
130        if kind == ParsingContext::EnumMembers {
131            let expect = P::Token::COMMA;
132            let cur = p.input().cur();
133            let cur = cur.clone().to_string(p.input());
134            p.emit_err(
135                p.input().cur_span(),
136                SyntaxError::Expected(format!("{expect:?}"), cur),
137            );
138            continue;
139        }
140        // This will fail with an error about a missing comma
141        expect!(p, &P::Token::COMMA);
142    }
143
144    Ok(buf)
145}
146
147/// In no lexer context
148pub(crate) fn ts_in_no_context<'a, P: Parser<'a>, T, F>(p: &mut P, op: F) -> PResult<T>
149where
150    F: FnOnce(&mut P) -> PResult<T>,
151{
152    debug_assert!(p.input().syntax().typescript());
153    trace_cur!(p, ts_in_no_context__before);
154    let saved = std::mem::take(p.input_mut().token_context_mut());
155    p.input_mut().token_context_mut().push(saved.0[0]);
156    debug_assert_eq!(p.input().token_context().len(), 1);
157    let res = op(p);
158    p.input_mut().set_token_context(saved);
159    trace_cur!(p, ts_in_no_context__after);
160    res
161}
162
163/// `tsIsListTerminator`
164fn is_ts_list_terminator<'a>(p: &mut impl Parser<'a>, kind: ParsingContext) -> bool {
165    debug_assert!(p.input().syntax().typescript());
166    let cur = p.input().cur();
167    match kind {
168        ParsingContext::EnumMembers | ParsingContext::TypeMembers => cur.is_rbrace(),
169        ParsingContext::HeritageClauseElement => {
170            cur.is_lbrace() || cur.is_implements() || cur.is_extends()
171        }
172        ParsingContext::TupleElementTypes => cur.is_rbracket(),
173        ParsingContext::TypeParametersOrArguments => cur.is_greater(),
174    }
175}
176
177/// `tsNextTokenCanFollowModifier`
178pub(super) fn ts_next_token_can_follow_modifier<'a>(p: &mut impl Parser<'a>) -> bool {
179    debug_assert!(p.input().syntax().typescript());
180    // Note: TypeScript's implementation is much more complicated because
181    // more things are considered modifiers there.
182    // This implementation only handles modifiers not handled by @babel/parser
183    // itself. And "static". TODO: Would be nice to avoid lookahead. Want a
184    // hasLineBreakUpNext() method...
185    p.bump();
186
187    let cur = p.input().cur();
188    !p.input().had_line_break_before_cur() && cur.is_lbracket()
189        || cur.is_lbrace()
190        || cur.is_star()
191        || cur.is_dotdotdot()
192        || cur.is_hash()
193        || cur.is_word()
194        || cur.is_str()
195        || cur.is_num()
196        || cur.is_bigint()
197}
198
199/// `tsTryParse`
200pub fn try_parse_ts<'a, P: Parser<'a>, T, F>(p: &mut P, op: F) -> Option<T>
201where
202    F: FnOnce(&mut P) -> PResult<Option<T>>,
203{
204    if !p.input().syntax().typescript() {
205        return None;
206    }
207    debug_tracing!(p, "try_parse_ts");
208
209    trace_cur!(p, try_parse_ts);
210
211    let prev_ignore_error = p.input().get_ctx().contains(Context::IgnoreError);
212    let checkpoint = p.checkpoint_save();
213    p.set_ctx(p.ctx() | Context::IgnoreError);
214    let res = op(p);
215    match res {
216        Ok(Some(res)) => {
217            trace_cur!(p, try_parse_ts__success_value);
218            let mut ctx = p.ctx();
219            ctx.set(Context::IgnoreError, prev_ignore_error);
220            p.input_mut().set_ctx(ctx);
221            Some(res)
222        }
223        Ok(None) => {
224            trace_cur!(p, try_parse_ts__success_no_value);
225            p.checkpoint_load(checkpoint);
226            None
227        }
228        Err(..) => {
229            trace_cur!(p, try_parse_ts__fail);
230            p.checkpoint_load(checkpoint);
231            None
232        }
233    }
234}
235
236/// `tsParseTypeMemberSemicolon`
237fn parse_ts_type_member_semicolon<'a, P: Parser<'a>>(p: &mut P) -> PResult<()> {
238    debug_assert!(p.input().syntax().typescript());
239
240    if !p.input_mut().eat(&P::Token::COMMA) {
241        p.expect_general_semi()
242    } else {
243        Ok(())
244    }
245}
246
247/// `tsIsStartOfConstructSignature`
248fn is_ts_start_of_construct_signature<'a, P: Parser<'a>>(p: &mut P) -> bool {
249    debug_assert!(p.input().syntax().typescript());
250
251    p.bump();
252    let cur = p.input().cur();
253    cur.is_lparen() || cur.is_less()
254}
255
256/// `tsParseDelimitedList`
257fn parse_ts_delimited_list<'a, P: Parser<'a>, T, F>(
258    p: &mut P,
259    kind: ParsingContext,
260    mut parse_element: F,
261) -> PResult<Vec<T>>
262where
263    F: FnMut(&mut P) -> PResult<T>,
264{
265    parse_ts_delimited_list_inner(p, kind, |p| {
266        let start = p.input().cur_pos();
267        Ok((start, parse_element(p)?))
268    })
269}
270
271/// `tsParseUnionOrIntersectionType`
272fn parse_ts_union_or_intersection_type<'a, P: Parser<'a>, F>(
273    p: &mut P,
274    kind: UnionOrIntersection,
275    mut parse_constituent_type: F,
276    operator: &P::Token,
277) -> PResult<Box<TsType>>
278where
279    F: FnMut(&mut P) -> PResult<Box<TsType>>,
280{
281    trace_cur!(p, parse_ts_union_or_intersection_type);
282
283    debug_assert!(p.input().syntax().typescript());
284
285    let start = p.input().cur_pos(); // include the leading operator in the start
286    p.input_mut().eat(operator);
287    trace_cur!(p, parse_ts_union_or_intersection_type__first_type);
288
289    let ty = parse_constituent_type(p)?;
290    trace_cur!(p, parse_ts_union_or_intersection_type__after_first);
291
292    if p.input().is(operator) {
293        let mut types = vec![ty];
294
295        while p.input_mut().eat(operator) {
296            trace_cur!(p, parse_ts_union_or_intersection_type__constituent);
297
298            types.push(parse_constituent_type(p)?);
299        }
300
301        return Ok(Box::new(TsType::TsUnionOrIntersectionType(match kind {
302            UnionOrIntersection::Union => TsUnionOrIntersectionType::TsUnionType(TsUnionType {
303                span: p.span(start),
304                types,
305            }),
306            UnionOrIntersection::Intersection => {
307                TsUnionOrIntersectionType::TsIntersectionType(TsIntersectionType {
308                    span: p.span(start),
309                    types,
310                })
311            }
312        })));
313    }
314    Ok(ty)
315}
316
317pub fn eat_any_ts_modifier<'a>(p: &mut impl Parser<'a>) -> PResult<bool> {
318    if p.syntax().typescript()
319        && {
320            let cur = p.input().cur();
321            cur.is_public() || cur.is_protected() || cur.is_private() || cur.is_readonly()
322        }
323        && peek!(p).is_some_and(|t| t.is_word() || t.is_lbrace() || t.is_lbracket())
324    {
325        let _ = parse_ts_modifier(p, &["public", "protected", "private", "readonly"], false);
326        Ok(true)
327    } else {
328        Ok(false)
329    }
330}
331
332/// Parses a modifier matching one the given modifier names.
333///
334/// `tsParseModifier`
335pub fn parse_ts_modifier<'a, P: Parser<'a>>(
336    p: &mut P,
337    allowed_modifiers: &[&'static str],
338    stop_on_start_of_class_static_blocks: bool,
339) -> PResult<Option<&'static str>> {
340    debug_assert!(p.input().syntax().typescript());
341    let pos = {
342        let cur = p.input().cur();
343        let modifier = if cur.is_unknown_ident() {
344            cur.clone().take_unknown_ident_ref(p.input()).clone()
345        } else if cur.is_known_ident() {
346            cur.take_known_ident()
347        } else if cur.is_in() {
348            atom!("in")
349        } else if cur.is_const() {
350            atom!("const")
351        } else if cur.is_error() {
352            let err = p.input_mut().expect_error_token_and_bump();
353            return Err(err);
354        } else if cur.is_eof() {
355            return Err(eof_error(p));
356        } else {
357            return Ok(None);
358        };
359        // TODO: compare atom rather than string.
360        allowed_modifiers
361            .iter()
362            .position(|s| **s == *modifier.as_str())
363    };
364    if let Some(pos) = pos {
365        if stop_on_start_of_class_static_blocks
366            && p.input().is(&P::Token::STATIC)
367            && peek!(p).is_some_and(|peek| peek.is_lbrace())
368        {
369            return Ok(None);
370        }
371        if try_parse_ts_bool(p, |p| Ok(Some(ts_next_token_can_follow_modifier(p))))? {
372            return Ok(Some(allowed_modifiers[pos]));
373        }
374    }
375    Ok(None)
376}
377
378fn parse_ts_bracketed_list<'a, P: Parser<'a>, T, F>(
379    p: &mut P,
380    kind: ParsingContext,
381    parse_element: F,
382    bracket: bool,
383    skip_first_token: bool,
384) -> PResult<Vec<T>>
385where
386    F: FnMut(&mut P) -> PResult<T>,
387{
388    debug_assert!(p.input().syntax().typescript());
389    if !skip_first_token {
390        if bracket {
391            expect!(p, &P::Token::LBRACKET);
392        } else {
393            expect!(p, &P::Token::LESS);
394        }
395    }
396    let result = parse_ts_delimited_list(p, kind, parse_element)?;
397    if bracket {
398        expect!(p, &P::Token::RBRACKET);
399    } else {
400        expect!(p, &P::Token::GREATER);
401    }
402    Ok(result)
403}
404
405/// `tsParseThisTypeNode`
406pub fn parse_ts_this_type_node<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsThisType> {
407    debug_assert!(p.input().syntax().typescript());
408    expect!(p, &P::Token::THIS);
409    Ok(TsThisType {
410        span: p.input().prev_span(),
411    })
412}
413
414/// `tsParseEntityName`
415pub fn parse_ts_entity_name<'a, P: Parser<'a>>(
416    p: &mut P,
417    allow_reserved_words: bool,
418) -> PResult<TsEntityName> {
419    debug_assert!(p.input().syntax().typescript());
420    trace_cur!(p, parse_ts_entity_name);
421    let start = p.input().cur_pos();
422    let init = parse_ident_name(p)?;
423    if &*init.sym == "void" {
424        let dot_start = p.input().cur_pos();
425        let dot_span = p.span(dot_start);
426        p.emit_err(dot_span, SyntaxError::TS1005)
427    }
428    let mut entity = TsEntityName::Ident(init.into());
429    while p.input_mut().eat(&P::Token::DOT) {
430        let dot_start = p.input().cur_pos();
431        let cur = p.input().cur();
432        if !cur.is_hash() && !cur.is_word() {
433            p.emit_err(
434                Span::new_with_checked(dot_start, dot_start),
435                SyntaxError::TS1003,
436            );
437            return Ok(entity);
438        }
439        let left = entity;
440        let right = if allow_reserved_words {
441            parse_ident_name(p)?
442        } else {
443            parse_ident(p, false, false)?.into()
444        };
445        let span = p.span(start);
446        entity = TsEntityName::TsQualifiedName(Box::new(TsQualifiedName { span, left, right }));
447    }
448    Ok(entity)
449}
450
451pub fn ts_look_ahead<'a, P: Parser<'a>, T, F>(p: &mut P, op: F) -> T
452where
453    F: FnOnce(&mut P) -> T,
454{
455    debug_assert!(p.input().syntax().typescript());
456    let checkpoint = p.checkpoint_save();
457    p.set_ctx(p.ctx() | Context::IgnoreError);
458    let ret = op(p);
459    p.checkpoint_load(checkpoint);
460    ret
461}
462
463/// `tsParseTypeArguments`
464pub fn parse_ts_type_args<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsTypeParamInstantiation>> {
465    trace_cur!(p, parse_ts_type_args);
466    debug_assert!(p.input().syntax().typescript());
467
468    let start = p.input().cur_pos();
469    let params = p.in_type(|p| {
470        // Temporarily remove a JSX parsing context, which makes us scan different
471        // tokens.
472        p.ts_in_no_context(|p| {
473            if p.input().is(&P::Token::LSHIFT) {
474                p.input_mut().cut_lshift();
475            } else {
476                expect!(p, &P::Token::LESS);
477            }
478            parse_ts_delimited_list(p, ParsingContext::TypeParametersOrArguments, |p| {
479                trace_cur!(p, parse_ts_type_args__arg);
480
481                parse_ts_type(p)
482            })
483        })
484    })?;
485    // This reads the next token after the `>` too, so do this in the enclosing
486    // context. But be sure not to parse a regex in the jsx expression
487    // `<C<number> />`, so set exprAllowed = false
488    p.input_mut().set_expr_allowed(false);
489    p.expect_without_advance(&P::Token::GREATER)?;
490    let span = Span::new_with_checked(start, p.input().cur_span().hi);
491    Ok(Box::new(TsTypeParamInstantiation { span, params }))
492}
493
494/// `tsParseTypeReference`
495pub fn parse_ts_type_ref<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTypeRef> {
496    trace_cur!(p, parse_ts_type_ref);
497    debug_assert!(p.input().syntax().typescript());
498
499    let start = p.input().cur_pos();
500
501    let has_modifier = eat_any_ts_modifier(p)?;
502
503    let type_name = parse_ts_entity_name(p, /* allow_reserved_words */ true)?;
504    trace_cur!(p, parse_ts_type_ref__type_args);
505    let type_params = if !p.input().had_line_break_before_cur()
506        && (p.input().is(&P::Token::LESS) || p.input().is(&P::Token::LSHIFT))
507    {
508        let ret = p.do_outside_of_context(Context::ShouldNotLexLtOrGtAsType, parse_ts_type_args)?;
509        p.assert_and_bump(&P::Token::GREATER);
510        Some(ret)
511    } else {
512        None
513    };
514
515    if has_modifier {
516        p.emit_err(p.span(start), SyntaxError::TS2369);
517    }
518
519    Ok(TsTypeRef {
520        span: p.span(start),
521        type_name,
522        type_params,
523    })
524}
525
526#[cfg_attr(
527    feature = "tracing-spans",
528    tracing::instrument(level = "debug", skip_all)
529)]
530pub fn parse_ts_type_ann<'a, P: Parser<'a>>(
531    p: &mut P,
532    eat_colon: bool,
533    start: BytePos,
534) -> PResult<Box<TsTypeAnn>> {
535    trace_cur!(p, parse_ts_type_ann);
536
537    debug_assert!(p.input().syntax().typescript());
538
539    p.in_type(|p| {
540        if eat_colon {
541            p.assert_and_bump(&P::Token::COLON);
542        }
543
544        trace_cur!(p, parse_ts_type_ann__after_colon);
545
546        let type_ann = parse_ts_type(p)?;
547
548        Ok(Box::new(TsTypeAnn {
549            span: p.span(start),
550            type_ann,
551        }))
552    })
553}
554
555/// `tsParseThisTypePredicate`
556pub fn parse_ts_this_type_predicate<'a, P: Parser<'a>>(
557    p: &mut P,
558    start: BytePos,
559    has_asserts_keyword: bool,
560    lhs: TsThisType,
561) -> PResult<TsTypePredicate> {
562    debug_assert!(p.input().syntax().typescript());
563
564    let param_name = TsThisTypeOrIdent::TsThisType(lhs);
565    let type_ann = if p.input_mut().eat(&P::Token::IS) {
566        let cur_pos = p.input().cur_pos();
567        Some(parse_ts_type_ann(
568            p, // eat_colon
569            false, cur_pos,
570        )?)
571    } else {
572        None
573    };
574
575    Ok(TsTypePredicate {
576        span: p.span(start),
577        asserts: has_asserts_keyword,
578        param_name,
579        type_ann,
580    })
581}
582
583/// `tsEatThenParseType`
584fn eat_then_parse_ts_type<'a, P: Parser<'a>>(
585    p: &mut P,
586    token_to_eat: &P::Token,
587) -> PResult<Option<Box<TsType>>> {
588    if !cfg!(feature = "typescript") {
589        return Ok(Default::default());
590    }
591
592    p.in_type(|p| {
593        if !p.input_mut().eat(token_to_eat) {
594            return Ok(None);
595        }
596
597        parse_ts_type(p).map(Some)
598    })
599}
600
601/// `tsExpectThenParseType`
602fn expect_then_parse_ts_type<'a, P: Parser<'a>>(
603    p: &mut P,
604    token: &P::Token,
605    token_str: &'static str,
606) -> PResult<Box<TsType>> {
607    debug_assert!(p.input().syntax().typescript());
608
609    p.in_type(|p| {
610        if !p.input_mut().eat(token) {
611            let got = format!("{:?}", p.input().cur());
612            syntax_error!(
613                p,
614                p.input().cur_span(),
615                SyntaxError::Unexpected {
616                    got,
617                    expected: token_str
618                }
619            );
620        }
621
622        parse_ts_type(p)
623    })
624}
625
626/// `tsParseMappedTypeParameter`
627fn parse_ts_mapped_type_param<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTypeParam> {
628    debug_assert!(p.input().syntax().typescript());
629
630    let start = p.input().cur_pos();
631    let name = parse_ident_name(p)?;
632    let constraint = Some(expect_then_parse_ts_type(p, &P::Token::IN, "in")?);
633
634    Ok(TsTypeParam {
635        span: p.span(start),
636        name: name.into(),
637        is_in: false,
638        is_out: false,
639        is_const: false,
640        constraint,
641        default: None,
642    })
643}
644
645/// `tsParseTypeParameter`
646fn parse_ts_type_param<'a, P: Parser<'a>>(
647    p: &mut P,
648    permit_in_out: bool,
649    permit_const: bool,
650) -> PResult<TsTypeParam> {
651    debug_assert!(p.input().syntax().typescript());
652
653    let mut is_in = false;
654    let mut is_out = false;
655    let mut is_const = false;
656
657    let start = p.input().cur_pos();
658
659    while let Some(modifer) = parse_ts_modifier(
660        p,
661        &[
662            "public",
663            "private",
664            "protected",
665            "readonly",
666            "abstract",
667            "const",
668            "override",
669            "in",
670            "out",
671        ],
672        false,
673    )? {
674        match modifer {
675            "const" => {
676                is_const = true;
677                if !permit_const {
678                    p.emit_err(p.input().prev_span(), SyntaxError::TS1277(atom!("const")));
679                }
680            }
681            "in" => {
682                if !permit_in_out {
683                    p.emit_err(p.input().prev_span(), SyntaxError::TS1274(atom!("in")));
684                } else if is_in {
685                    p.emit_err(p.input().prev_span(), SyntaxError::TS1030(atom!("in")));
686                } else if is_out {
687                    p.emit_err(
688                        p.input().prev_span(),
689                        SyntaxError::TS1029(atom!("in"), atom!("out")),
690                    );
691                }
692                is_in = true;
693            }
694            "out" => {
695                if !permit_in_out {
696                    p.emit_err(p.input().prev_span(), SyntaxError::TS1274(atom!("out")));
697                } else if is_out {
698                    p.emit_err(p.input().prev_span(), SyntaxError::TS1030(atom!("out")));
699                }
700                is_out = true;
701            }
702            other => p.emit_err(p.input().prev_span(), SyntaxError::TS1273(other.into())),
703        };
704    }
705
706    let name = p.in_type(parse_ident_name)?.into();
707    let constraint = eat_then_parse_ts_type(p, &P::Token::EXTENDS)?;
708    let default = eat_then_parse_ts_type(p, &P::Token::EQUAL)?;
709
710    Ok(TsTypeParam {
711        span: p.span(start),
712        name,
713        is_in,
714        is_out,
715        is_const,
716        constraint,
717        default,
718    })
719}
720
721/// `tsParseTypeParameter`
722pub fn parse_ts_type_params<'a, P: Parser<'a>>(
723    p: &mut P,
724    permit_in_out: bool,
725    permit_const: bool,
726) -> PResult<Box<TsTypeParamDecl>> {
727    p.in_type(|p| {
728        p.ts_in_no_context(|p| {
729            let start = p.input().cur_pos();
730            let cur = p.input().cur();
731            if !cur.is_less() && !cur.is_jsx_tag_start() {
732                unexpected!(p, "< (jsx tag start)")
733            }
734            p.bump();
735
736            let params = parse_ts_bracketed_list(
737                p,
738                ParsingContext::TypeParametersOrArguments,
739                |p| parse_ts_type_param(p, permit_in_out, permit_const), // bracket
740                false,
741                // skip_first_token
742                true,
743            )?;
744
745            Ok(Box::new(TsTypeParamDecl {
746                span: p.span(start),
747                params,
748            }))
749        })
750    })
751}
752
753/// `tsTryParseTypeParameters`
754pub fn try_parse_ts_type_params<'a, P: Parser<'a>>(
755    p: &mut P,
756    permit_in_out: bool,
757    permit_const: bool,
758) -> PResult<Option<Box<TsTypeParamDecl>>> {
759    if !cfg!(feature = "typescript") {
760        return Ok(None);
761    }
762
763    if p.input().cur().is_less() {
764        return parse_ts_type_params(p, permit_in_out, permit_const).map(Some);
765    }
766
767    Ok(None)
768}
769
770/// `tsParseTypeOrTypePredicateAnnotation`
771pub fn parse_ts_type_or_type_predicate_ann<'a, P: Parser<'a>>(
772    p: &mut P,
773    return_token: &P::Token,
774) -> PResult<Box<TsTypeAnn>> {
775    debug_assert!(p.input().syntax().typescript());
776
777    p.in_type(|p| {
778        let return_token_start = p.input().cur_pos();
779        if !p.input_mut().eat(return_token) {
780            let cur = format!("{:?}", p.input().cur());
781            let span = p.input().cur_span();
782            syntax_error!(
783                p,
784                span,
785                SyntaxError::Expected(format!("{return_token:?}"), cur)
786            )
787        }
788
789        let type_pred_start = p.input().cur_pos();
790        let has_type_pred_asserts = p.input().cur().is_asserts() && {
791            let ctx = p.ctx();
792            peek!(p).is_some_and(|peek| {
793                if peek.is_word() {
794                    !peek.is_reserved(ctx)
795                } else {
796                    false
797                }
798            })
799        };
800
801        if has_type_pred_asserts {
802            p.assert_and_bump(&P::Token::ASSERTS);
803        }
804
805        let has_type_pred_is = p.is_ident_ref()
806            && peek!(p).is_some_and(|peek| peek.is_is())
807            && !p.input_mut().has_linebreak_between_cur_and_peeked();
808        let is_type_predicate = has_type_pred_asserts || has_type_pred_is;
809        if !is_type_predicate {
810            return parse_ts_type_ann(
811                p,
812                // eat_colon
813                false,
814                return_token_start,
815            );
816        }
817
818        let type_pred_var = parse_ident_name(p)?;
819        let type_ann = if has_type_pred_is {
820            p.assert_and_bump(&P::Token::IS);
821            let pos = p.input().cur_pos();
822            Some(parse_ts_type_ann(
823                p, // eat_colon
824                false, pos,
825            )?)
826        } else {
827            None
828        };
829
830        let node = Box::new(TsType::TsTypePredicate(TsTypePredicate {
831            span: p.span(type_pred_start),
832            asserts: has_type_pred_asserts,
833            param_name: TsThisTypeOrIdent::Ident(type_pred_var.into()),
834            type_ann,
835        }));
836
837        Ok(Box::new(TsTypeAnn {
838            span: p.span(return_token_start),
839            type_ann: node,
840        }))
841    })
842}
843
844fn is_start_of_expr<'a>(p: &mut impl Parser<'a>) -> bool {
845    is_start_of_left_hand_side_expr(p) || {
846        let cur = p.input().cur();
847        cur.is_plus()
848            || cur.is_minus()
849            || cur.is_tilde()
850            || cur.is_bang()
851            || cur.is_delete()
852            || cur.is_typeof()
853            || cur.is_void()
854            || cur.is_plus_plus()
855            || cur.is_minus_minus()
856            || cur.is_less()
857            || cur.is_await()
858            || cur.is_yield()
859            || (cur.is_hash() && peek!(p).is_some_and(|peek| peek.is_word()))
860    }
861}
862
863#[cfg_attr(
864    feature = "tracing-spans",
865    tracing::instrument(level = "debug", skip_all)
866)]
867pub(super) fn try_parse_ts_type_args<'a, P: Parser<'a>>(
868    p: &mut P,
869) -> Option<Box<TsTypeParamInstantiation>> {
870    trace_cur!(p, try_parse_ts_type_args);
871    debug_assert!(p.input().syntax().typescript());
872
873    try_parse_ts(p, |p| {
874        let type_args = parse_ts_type_args(p)?;
875        p.assert_and_bump(&P::Token::GREATER);
876        let cur = p.input().cur();
877        if cur.is_less() // invalid syntax
878            || cur.is_greater() || cur.is_equal() || cur.is_rshift() || cur.is_greater_eq() || cur.is_plus() || cur.is_minus() // becomes relational expression
879            || cur.is_lparen() || cur.is_no_substitution_template_literal() || cur.is_template_head() || cur.is_backquote()
880        // these should be type
881        // arguments in function
882        // call or template, not
883        // instantiation
884        // expression
885        {
886            Ok(None)
887        } else if p.input().had_line_break_before_cur()
888            || p.input().cur().is_bin_op()
889            || !is_start_of_expr(p)
890        {
891            Ok(Some(type_args))
892        } else {
893            Ok(None)
894        }
895    })
896}
897
898/// `tsTryParseType`
899fn try_parse_ts_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<Option<Box<TsType>>> {
900    if !cfg!(feature = "typescript") {
901        return Ok(None);
902    }
903
904    eat_then_parse_ts_type(p, &P::Token::COLON)
905}
906
907/// `tsTryParseTypeAnnotation`
908#[cfg_attr(
909    feature = "tracing-spans",
910    tracing::instrument(level = "debug", skip_all)
911)]
912pub fn try_parse_ts_type_ann<'a, P: Parser<'a>>(p: &mut P) -> PResult<Option<Box<TsTypeAnn>>> {
913    if !cfg!(feature = "typescript") {
914        return Ok(None);
915    }
916
917    if p.input().is(&P::Token::COLON) {
918        let pos = p.cur_pos();
919        return parse_ts_type_ann(p, /* eat_colon */ true, pos).map(Some);
920    }
921
922    Ok(None)
923}
924
925/// `tsNextThenParseType`
926pub(super) fn next_then_parse_ts_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
927    debug_assert!(p.input().syntax().typescript());
928
929    let result = p.in_type(|p| {
930        p.bump();
931        parse_ts_type(p)
932    });
933
934    if !p.ctx().contains(Context::InType) && {
935        let cur = p.input().cur();
936        cur.is_less() || cur.is_greater()
937    } {
938        p.input_mut().merge_lt_gt();
939    }
940
941    result
942}
943
944/// `tsParseEnumMember`
945fn parse_ts_enum_member<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsEnumMember> {
946    debug_assert!(p.input().syntax().typescript());
947
948    let start = p.cur_pos();
949    // Computed property names are grammar errors in an enum, so accept just string
950    // literal or identifier.
951    let cur = p.input().cur();
952    let id = if cur.is_str() {
953        TsEnumMemberId::Str(parse_str_lit(p))
954    } else if cur.is_num() {
955        let (value, raw) = p.input_mut().expect_number_token_and_bump();
956        let mut new_raw = String::new();
957
958        new_raw.push('"');
959        new_raw.push_str(raw.as_str());
960        new_raw.push('"');
961
962        let span = p.span(start);
963
964        // Recover from error
965        p.emit_err(span, SyntaxError::TS2452);
966
967        TsEnumMemberId::Str(Str {
968            span,
969            value: value.to_string().into(),
970            raw: Some(new_raw.into()),
971        })
972    } else if cur.is_lbracket() {
973        p.assert_and_bump(&P::Token::LBRACKET);
974        let _ = p.parse_expr()?;
975        p.emit_err(p.span(start), SyntaxError::TS1164);
976        p.assert_and_bump(&P::Token::RBRACKET);
977        TsEnumMemberId::Ident(Ident::new_no_ctxt(atom!(""), p.span(start)))
978    } else if cur.is_error() {
979        let err = p.input_mut().expect_error_token_and_bump();
980        return Err(err);
981    } else {
982        parse_ident_name(p)
983            .map(Ident::from)
984            .map(TsEnumMemberId::from)?
985    };
986
987    let init = if p.input_mut().eat(&P::Token::EQUAL) {
988        Some(parse_assignment_expr(p)?)
989    } else if p.input().cur().is_comma() || p.input().cur().is_rbrace() {
990        None
991    } else {
992        let start = p.cur_pos();
993        p.bump();
994        p.input_mut().store(P::Token::COMMA);
995        p.emit_err(Span::new_with_checked(start, start), SyntaxError::TS1005);
996        None
997    };
998
999    Ok(TsEnumMember {
1000        span: p.span(start),
1001        id,
1002        init,
1003    })
1004}
1005
1006/// `tsParseEnumDeclaration`
1007pub fn parse_ts_enum_decl<'a, P: Parser<'a>>(
1008    p: &mut P,
1009    start: BytePos,
1010    is_const: bool,
1011) -> PResult<Box<TsEnumDecl>> {
1012    debug_assert!(p.input().syntax().typescript());
1013
1014    let id = parse_ident_name(p)?;
1015    expect!(p, &P::Token::LBRACE);
1016    let members = parse_ts_delimited_list(p, ParsingContext::EnumMembers, parse_ts_enum_member)?;
1017    expect!(p, &P::Token::RBRACE);
1018
1019    Ok(Box::new(TsEnumDecl {
1020        span: p.span(start),
1021        declare: false,
1022        is_const,
1023        id: id.into(),
1024        members,
1025    }))
1026}
1027
1028/// `tsTryParseTypeOrTypePredicateAnnotation`
1029///
1030/// Used for parsing return types.
1031pub fn try_parse_ts_type_or_type_predicate_ann<'a, P: Parser<'a>>(
1032    p: &mut P,
1033) -> PResult<Option<Box<TsTypeAnn>>> {
1034    if !cfg!(feature = "typescript") {
1035        return Ok(None);
1036    }
1037
1038    if p.input().is(&P::Token::COLON) {
1039        parse_ts_type_or_type_predicate_ann(p, &P::Token::COLON).map(Some)
1040    } else {
1041        Ok(None)
1042    }
1043}
1044
1045/// `tsParseTemplateLiteralType`
1046fn parse_ts_tpl_lit_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTplLitType> {
1047    debug_assert!(p.input().syntax().typescript());
1048
1049    let start = p.cur_pos();
1050
1051    p.assert_and_bump(&P::Token::BACKQUOTE);
1052
1053    let (types, quasis) = parse_ts_tpl_type_elements(p)?;
1054
1055    expect!(p, &P::Token::BACKQUOTE);
1056
1057    Ok(TsTplLitType {
1058        span: p.span(start),
1059        types,
1060        quasis,
1061    })
1062}
1063
1064fn parse_ts_tpl_type_elements<'a, P: Parser<'a>>(
1065    p: &mut P,
1066) -> PResult<(Vec<Box<TsType>>, Vec<TplElement>)> {
1067    if !cfg!(feature = "typescript") {
1068        return Ok(Default::default());
1069    }
1070
1071    trace_cur!(p, parse_tpl_elements);
1072
1073    let mut types = Vec::new();
1074
1075    let cur_elem = p.parse_tpl_element(false)?;
1076    let mut is_tail = cur_elem.tail;
1077    let mut quasis = vec![cur_elem];
1078
1079    while !is_tail {
1080        expect!(p, &P::Token::DOLLAR_LBRACE);
1081        types.push(parse_ts_type(p)?);
1082        expect!(p, &P::Token::RBRACE);
1083        let elem = p.parse_tpl_element(false)?;
1084        is_tail = elem.tail;
1085        quasis.push(elem);
1086    }
1087
1088    Ok((types, quasis))
1089}
1090
1091/// `tsParseLiteralTypeNode`
1092fn parse_ts_lit_type_node<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsLitType> {
1093    debug_assert!(p.input().syntax().typescript());
1094
1095    let start = p.cur_pos();
1096
1097    let lit = if p.input().is(&P::Token::BACKQUOTE) {
1098        let tpl = parse_ts_tpl_lit_type(p)?;
1099        TsLit::Tpl(tpl)
1100    } else {
1101        match parse_lit(p)? {
1102            Lit::BigInt(n) => TsLit::BigInt(n),
1103            Lit::Bool(n) => TsLit::Bool(n),
1104            Lit::Num(n) => TsLit::Number(n),
1105            Lit::Str(n) => TsLit::Str(n),
1106            _ => unreachable!(),
1107        }
1108    };
1109
1110    Ok(TsLitType {
1111        span: p.span(start),
1112        lit,
1113    })
1114}
1115
1116/// `tsParseHeritageClause`
1117pub fn parse_ts_heritage_clause<'a>(p: &mut impl Parser<'a>) -> PResult<Vec<TsExprWithTypeArgs>> {
1118    debug_assert!(p.input().syntax().typescript());
1119
1120    parse_ts_delimited_list(
1121        p,
1122        ParsingContext::HeritageClauseElement,
1123        parse_ts_heritage_clause_element,
1124    )
1125}
1126
1127fn parse_ts_heritage_clause_element<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsExprWithTypeArgs> {
1128    debug_assert!(p.input().syntax().typescript());
1129
1130    let start = p.cur_pos();
1131    // Note: TS uses parseLeftHandSideExpressionOrHigher,
1132    // then has grammar errors later if it's not an EntityName.
1133
1134    let ident = parse_ident_name(p)?.into();
1135    let expr = parse_subscripts(p, Callee::Expr(ident), true, true)?;
1136    if !matches!(
1137        &*expr,
1138        Expr::Ident(..) | Expr::Member(..) | Expr::TsInstantiation(..)
1139    ) {
1140        p.emit_err(p.span(start), SyntaxError::TS2499);
1141    }
1142
1143    match *expr {
1144        Expr::TsInstantiation(v) => Ok(TsExprWithTypeArgs {
1145            span: v.span,
1146            expr: v.expr,
1147            type_args: Some(v.type_args),
1148        }),
1149        _ => {
1150            let type_args = if p.input().is(&P::Token::LESS) {
1151                let ret = parse_ts_type_args(p)?;
1152                p.assert_and_bump(&P::Token::GREATER);
1153                Some(ret)
1154            } else {
1155                None
1156            };
1157
1158            Ok(TsExprWithTypeArgs {
1159                span: p.span(start),
1160                expr,
1161                type_args,
1162            })
1163        }
1164    }
1165}
1166
1167/// `tsSkipParameterStart`
1168fn skip_ts_parameter_start<'a, P: Parser<'a>>(p: &mut P) -> PResult<bool> {
1169    debug_assert!(p.input().syntax().typescript());
1170
1171    let _ = eat_any_ts_modifier(p)?;
1172
1173    let cur = p.input().cur();
1174    if cur.is_word() || cur.is_this() {
1175        p.bump();
1176        Ok(true)
1177    } else if (cur.is_lbrace() || cur.is_lbracket()) && parse_binding_pat_or_ident(p, false).is_ok()
1178    {
1179        Ok(true)
1180    } else {
1181        Ok(false)
1182    }
1183}
1184
1185/// `tsIsUnambiguouslyStartOfFunctionType`
1186fn is_ts_unambiguously_start_of_fn_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<bool> {
1187    debug_assert!(p.input().syntax().typescript());
1188
1189    p.assert_and_bump(&P::Token::LPAREN);
1190
1191    let cur = p.input().cur();
1192    if cur.is_rparen() || cur.is_dotdotdot() {
1193        // ( )
1194        // ( ...
1195        return Ok(true);
1196    }
1197    if skip_ts_parameter_start(p)? {
1198        let cur = p.input().cur();
1199        if cur.is_colon() || cur.is_comma() || cur.is_equal() || cur.is_question() {
1200            // ( xxx :
1201            // ( xxx ,
1202            // ( xxx ?
1203            // ( xxx =
1204            return Ok(true);
1205        }
1206        if p.input_mut().eat(&P::Token::RPAREN) && p.input().cur().is_arrow() {
1207            // ( xxx ) =>
1208            return Ok(true);
1209        }
1210    }
1211    Ok(false)
1212}
1213
1214fn is_ts_start_of_fn_type<'a, P: Parser<'a>>(p: &mut P) -> bool {
1215    debug_assert!(p.input().syntax().typescript());
1216
1217    if p.input().cur().is_less() {
1218        return true;
1219    }
1220
1221    p.input().cur().is_lparen()
1222        && ts_look_ahead(p, is_ts_unambiguously_start_of_fn_type).unwrap_or_default()
1223}
1224
1225/// `tsIsUnambiguouslyIndexSignature`
1226fn is_ts_unambiguously_index_signature<'a, P: Parser<'a>>(p: &mut P) -> bool {
1227    debug_assert!(p.input().syntax().typescript());
1228
1229    // Note: babel's comment is wrong
1230    p.assert_and_bump(&P::Token::LBRACKET); // Skip '['
1231
1232    // ',' is for error recovery
1233    p.eat_ident_ref() && {
1234        let cur = p.input().cur();
1235        cur.is_comma() || cur.is_colon()
1236    }
1237}
1238
1239/// `tsTryParseIndexSignature`
1240pub fn try_parse_ts_index_signature<'a, P: Parser<'a>>(
1241    p: &mut P,
1242    index_signature_start: BytePos,
1243    readonly: bool,
1244    is_static: bool,
1245) -> PResult<Option<TsIndexSignature>> {
1246    if !cfg!(feature = "typescript") {
1247        return Ok(Default::default());
1248    }
1249
1250    if !(p.input().cur().is_lbracket() && ts_look_ahead(p, is_ts_unambiguously_index_signature)) {
1251        return Ok(None);
1252    }
1253
1254    expect!(p, &P::Token::LBRACKET);
1255
1256    let ident_start = p.cur_pos();
1257    let mut id = parse_ident_name(p).map(BindingIdent::from)?;
1258    let type_ann_start = p.cur_pos();
1259
1260    if p.input_mut().eat(&P::Token::COMMA) {
1261        p.emit_err(id.span, SyntaxError::TS1096);
1262    } else {
1263        expect!(p, &P::Token::COLON);
1264    }
1265
1266    let type_ann = parse_ts_type_ann(p, /* eat_colon */ false, type_ann_start)?;
1267    id.span = p.span(ident_start);
1268    id.type_ann = Some(type_ann);
1269
1270    expect!(p, &P::Token::RBRACKET);
1271
1272    let params = vec![TsFnParam::Ident(id)];
1273
1274    let ty = try_parse_ts_type_ann(p)?;
1275    let type_ann = ty;
1276
1277    parse_ts_type_member_semicolon(p)?;
1278
1279    Ok(Some(TsIndexSignature {
1280        span: p.span(index_signature_start),
1281        readonly,
1282        is_static,
1283        params,
1284        type_ann,
1285    }))
1286}
1287
1288/// `tsIsExternalModuleReference`
1289fn is_ts_external_module_ref<'a, P: Parser<'a>>(p: &mut P) -> bool {
1290    debug_assert!(p.input().syntax().typescript());
1291    p.input().is(&P::Token::REQUIRE) && peek!(p).is_some_and(|t| t.is_lparen())
1292}
1293
1294/// `tsParseModuleReference`
1295fn parse_ts_module_ref<'a>(p: &mut impl Parser<'a>) -> PResult<TsModuleRef> {
1296    debug_assert!(p.input().syntax().typescript());
1297
1298    if is_ts_external_module_ref(p) {
1299        parse_ts_external_module_ref(p).map(From::from)
1300    } else {
1301        parse_ts_entity_name(p, /* allow_reserved_words */ false).map(From::from)
1302    }
1303}
1304
1305/// `tsParseExternalModuleReference`
1306fn parse_ts_external_module_ref<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsExternalModuleRef> {
1307    debug_assert!(p.input().syntax().typescript());
1308
1309    let start = p.cur_pos();
1310    expect!(p, &P::Token::REQUIRE);
1311    expect!(p, &P::Token::LPAREN);
1312    let cur = p.input().cur();
1313    if cur.is_error() {
1314        let err = p.input_mut().expect_error_token_and_bump();
1315        return Err(err);
1316    } else if !cur.is_str() {
1317        unexpected!(p, "a string literal")
1318    }
1319    let expr = parse_str_lit(p);
1320    expect!(p, &P::Token::RPAREN);
1321    Ok(TsExternalModuleRef {
1322        span: p.span(start),
1323        expr,
1324    })
1325}
1326
1327/// `tsParseImportEqualsDeclaration`
1328pub fn parse_ts_import_equals_decl<'a, P: Parser<'a>>(
1329    p: &mut P,
1330    start: BytePos,
1331    id: Ident,
1332    is_export: bool,
1333    is_type_only: bool,
1334) -> PResult<Box<TsImportEqualsDecl>> {
1335    debug_assert!(p.input().syntax().typescript());
1336
1337    expect!(p, &P::Token::EQUAL);
1338    let module_ref = parse_ts_module_ref(p)?;
1339    p.expect_general_semi()?;
1340
1341    Ok(Box::new(TsImportEqualsDecl {
1342        span: p.span(start),
1343        id,
1344        is_export,
1345        is_type_only,
1346        module_ref,
1347    }))
1348}
1349
1350/// `tsParseBindingListForSignature`
1351///
1352/// Eats ')` at the end but does not eat `(` at start.
1353fn parse_ts_binding_list_for_signature<'a, P: Parser<'a>>(p: &mut P) -> PResult<Vec<TsFnParam>> {
1354    if !cfg!(feature = "typescript") {
1355        return Ok(Default::default());
1356    }
1357
1358    debug_assert!(p.input().syntax().typescript());
1359
1360    let params = parse_formal_params(p)?;
1361    let mut list = Vec::with_capacity(4);
1362
1363    for param in params {
1364        let item = match param.pat {
1365            Pat::Ident(pat) => TsFnParam::Ident(pat),
1366            Pat::Array(pat) => TsFnParam::Array(pat),
1367            Pat::Object(pat) => TsFnParam::Object(pat),
1368            Pat::Rest(pat) => TsFnParam::Rest(pat),
1369            _ => unexpected!(
1370                p,
1371                "an identifier, [ for an array pattern, { for an object patter or ... for a rest \
1372                 pattern"
1373            ),
1374        };
1375        list.push(item);
1376    }
1377    expect!(p, &P::Token::RPAREN);
1378    Ok(list)
1379}
1380
1381/// `tsIsStartOfMappedType`
1382pub fn is_ts_start_of_mapped_type<'a, P: Parser<'a>>(p: &mut P) -> bool {
1383    debug_assert!(p.input().syntax().typescript());
1384
1385    p.bump();
1386    if p.input_mut().eat(&P::Token::PLUS) || p.input_mut().eat(&P::Token::MINUS) {
1387        return p.input().is(&P::Token::READONLY);
1388    }
1389
1390    p.input_mut().eat(&P::Token::READONLY);
1391
1392    if !p.input().is(&P::Token::LBRACKET) {
1393        return false;
1394    }
1395    p.bump();
1396    if !p.is_ident_ref() {
1397        return false;
1398    }
1399    p.bump();
1400
1401    p.input().is(&P::Token::IN)
1402}
1403
1404/// `tsParseSignatureMember`
1405fn parse_ts_signature_member<'a, P: Parser<'a>>(
1406    p: &mut P,
1407    kind: SignatureParsingMode,
1408) -> PResult<Either<TsCallSignatureDecl, TsConstructSignatureDecl>> {
1409    debug_assert!(p.input().syntax().typescript());
1410
1411    let start = p.cur_pos();
1412
1413    if kind == SignatureParsingMode::TSConstructSignatureDeclaration {
1414        expect!(p, &P::Token::NEW);
1415    }
1416
1417    // ----- inlined p.tsFillSignature(tt.colon, node);
1418    let type_params = try_parse_ts_type_params(p, false, true)?;
1419    expect!(p, &P::Token::LPAREN);
1420    let params = parse_ts_binding_list_for_signature(p)?;
1421    let type_ann = if p.input().is(&P::Token::COLON) {
1422        Some(parse_ts_type_or_type_predicate_ann(p, &P::Token::COLON)?)
1423    } else {
1424        None
1425    };
1426    // -----
1427
1428    parse_ts_type_member_semicolon(p)?;
1429
1430    match kind {
1431        SignatureParsingMode::TSCallSignatureDeclaration => Ok(Either::Left(TsCallSignatureDecl {
1432            span: p.span(start),
1433            params,
1434            type_ann,
1435            type_params,
1436        })),
1437        SignatureParsingMode::TSConstructSignatureDeclaration => {
1438            Ok(Either::Right(TsConstructSignatureDecl {
1439                span: p.span(start),
1440                params,
1441                type_ann,
1442                type_params,
1443            }))
1444        }
1445    }
1446}
1447
1448fn try_parse_ts_tuple_element_name<'a, P: Parser<'a>>(p: &mut P) -> Option<Pat> {
1449    if !cfg!(feature = "typescript") {
1450        return Default::default();
1451    }
1452
1453    try_parse_ts(p, |p| {
1454        let start = p.cur_pos();
1455
1456        let rest = if p.input_mut().eat(&P::Token::DOTDOTDOT) {
1457            Some(p.input().prev_span())
1458        } else {
1459            None
1460        };
1461
1462        let mut ident = parse_ident_name(p).map(Ident::from)?;
1463        if p.input_mut().eat(&P::Token::QUESTION) {
1464            ident.optional = true;
1465            ident.span = ident.span.with_hi(p.input().prev_span().hi);
1466        }
1467        expect!(p, &P::Token::COLON);
1468
1469        Ok(Some(if let Some(dot3_token) = rest {
1470            RestPat {
1471                span: p.span(start),
1472                dot3_token,
1473                arg: ident.into(),
1474                type_ann: None,
1475            }
1476            .into()
1477        } else {
1478            ident.into()
1479        }))
1480    })
1481}
1482
1483/// `tsParseTupleElementType`
1484fn parse_ts_tuple_element_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTupleElement> {
1485    debug_assert!(p.input().syntax().typescript());
1486
1487    // parses `...TsType[]`
1488    let start = p.cur_pos();
1489
1490    let label = try_parse_ts_tuple_element_name(p);
1491
1492    if p.input_mut().eat(&P::Token::DOTDOTDOT) {
1493        let type_ann = parse_ts_type(p)?;
1494        return Ok(TsTupleElement {
1495            span: p.span(start),
1496            label,
1497            ty: Box::new(TsType::TsRestType(TsRestType {
1498                span: p.span(start),
1499                type_ann,
1500            })),
1501        });
1502    }
1503
1504    let ty = parse_ts_type(p)?;
1505    // parses `TsType?`
1506    if p.input_mut().eat(&P::Token::QUESTION) {
1507        let type_ann = ty;
1508        return Ok(TsTupleElement {
1509            span: p.span(start),
1510            label,
1511            ty: Box::new(TsType::TsOptionalType(TsOptionalType {
1512                span: p.span(start),
1513                type_ann,
1514            })),
1515        });
1516    }
1517
1518    Ok(TsTupleElement {
1519        span: p.span(start),
1520        label,
1521        ty,
1522    })
1523}
1524
1525/// `tsParseTupleType`
1526pub fn parse_ts_tuple_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTupleType> {
1527    debug_assert!(p.input().syntax().typescript());
1528
1529    let start = p.cur_pos();
1530    let elems = parse_ts_bracketed_list(
1531        p,
1532        ParsingContext::TupleElementTypes,
1533        parse_ts_tuple_element_type,
1534        /* bracket */ true,
1535        /* skipFirstToken */ false,
1536    )?;
1537
1538    // Validate the elementTypes to ensure:
1539    //   No mandatory elements may follow optional elements
1540    //   If there's a rest element, it must be at the end of the tuple
1541
1542    let mut seen_optional_element = false;
1543
1544    for elem in elems.iter() {
1545        match *elem.ty {
1546            TsType::TsRestType(..) => {}
1547            TsType::TsOptionalType(..) => {
1548                seen_optional_element = true;
1549            }
1550            _ if seen_optional_element => {
1551                syntax_error!(p, p.span(start), SyntaxError::TsRequiredAfterOptional)
1552            }
1553            _ => {}
1554        }
1555    }
1556
1557    Ok(TsTupleType {
1558        span: p.span(start),
1559        elem_types: elems,
1560    })
1561}
1562
1563/// `tsParseMappedType`
1564pub fn parse_ts_mapped_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsMappedType> {
1565    debug_assert!(p.input().syntax().typescript());
1566
1567    let start = p.cur_pos();
1568    expect!(p, &P::Token::LBRACE);
1569    let mut readonly = None;
1570    let cur = p.input().cur();
1571    if cur.is_plus() || cur.is_minus() {
1572        readonly = Some(if cur.is_plus() {
1573            TruePlusMinus::Plus
1574        } else {
1575            TruePlusMinus::Minus
1576        });
1577        p.bump();
1578        expect!(p, &P::Token::READONLY)
1579    } else if p.input_mut().eat(&P::Token::READONLY) {
1580        readonly = Some(TruePlusMinus::True);
1581    }
1582
1583    expect!(p, &P::Token::LBRACKET);
1584    let type_param = parse_ts_mapped_type_param(p)?;
1585    let name_type = if p.input_mut().eat(&P::Token::AS) {
1586        Some(parse_ts_type(p)?)
1587    } else {
1588        None
1589    };
1590    expect!(p, &P::Token::RBRACKET);
1591
1592    let mut optional = None;
1593    let cur = p.input().cur();
1594    if cur.is_plus() || cur.is_minus() {
1595        optional = Some(if cur.is_plus() {
1596            TruePlusMinus::Plus
1597        } else {
1598            TruePlusMinus::Minus
1599        });
1600        p.bump(); // +, -
1601        expect!(p, &P::Token::QUESTION);
1602    } else if p.input_mut().eat(&P::Token::QUESTION) {
1603        optional = Some(TruePlusMinus::True);
1604    }
1605
1606    let type_ann = try_parse_ts_type(p)?;
1607    p.expect_general_semi()?;
1608    expect!(p, &P::Token::RBRACE);
1609
1610    Ok(TsMappedType {
1611        span: p.span(start),
1612        readonly,
1613        optional,
1614        type_param,
1615        name_type,
1616        type_ann,
1617    })
1618}
1619
1620/// `tsParseParenthesizedType`
1621pub fn parse_ts_parenthesized_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsParenthesizedType> {
1622    debug_assert!(p.input().syntax().typescript());
1623    trace_cur!(p, parse_ts_parenthesized_type);
1624
1625    let start = p.cur_pos();
1626    expect!(p, &P::Token::LPAREN);
1627    let type_ann = parse_ts_type(p)?;
1628    expect!(p, &P::Token::RPAREN);
1629    Ok(TsParenthesizedType {
1630        span: p.span(start),
1631        type_ann,
1632    })
1633}
1634
1635/// `tsParseTypeAliasDeclaration`
1636pub fn parse_ts_type_alias_decl<'a, P: Parser<'a>>(
1637    p: &mut P,
1638    start: BytePos,
1639) -> PResult<Box<TsTypeAliasDecl>> {
1640    debug_assert!(p.input().syntax().typescript());
1641
1642    let id = parse_ident_name(p)?;
1643    let type_params = try_parse_ts_type_params(p, true, false)?;
1644    let type_ann = expect_then_parse_ts_type(p, &P::Token::EQUAL, "=")?;
1645    p.expect_general_semi()?;
1646    Ok(Box::new(TsTypeAliasDecl {
1647        declare: false,
1648        span: p.span(start),
1649        id: id.into(),
1650        type_params,
1651        type_ann,
1652    }))
1653}
1654
1655/// `tsParseFunctionOrConstructorType`
1656fn parse_ts_fn_or_constructor_type<'a, P: Parser<'a>>(
1657    p: &mut P,
1658    is_fn_type: bool,
1659) -> PResult<TsFnOrConstructorType> {
1660    trace_cur!(p, parse_ts_fn_or_constructor_type);
1661
1662    debug_assert!(p.input().syntax().typescript());
1663
1664    let start = p.cur_pos();
1665    let is_abstract = if !is_fn_type {
1666        p.input_mut().eat(&P::Token::ABSTRACT)
1667    } else {
1668        false
1669    };
1670    if !is_fn_type {
1671        expect!(p, &P::Token::NEW);
1672    }
1673
1674    // ----- inlined `p.tsFillSignature(tt.arrow, node)`
1675    let type_params = try_parse_ts_type_params(p, false, true)?;
1676    expect!(p, &P::Token::LPAREN);
1677    let params = parse_ts_binding_list_for_signature(p)?;
1678    let type_ann = parse_ts_type_or_type_predicate_ann(p, &P::Token::ARROW)?;
1679    // ----- end
1680
1681    Ok(if is_fn_type {
1682        TsFnOrConstructorType::TsFnType(TsFnType {
1683            span: p.span(start),
1684            type_params,
1685            params,
1686            type_ann,
1687        })
1688    } else {
1689        TsFnOrConstructorType::TsConstructorType(TsConstructorType {
1690            span: p.span(start),
1691            type_params,
1692            params,
1693            type_ann,
1694            is_abstract,
1695        })
1696    })
1697}
1698
1699/// `tsParseUnionTypeOrHigher`
1700fn parse_ts_union_type_or_higher<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
1701    trace_cur!(p, parse_ts_union_type_or_higher);
1702    debug_assert!(p.input().syntax().typescript());
1703
1704    parse_ts_union_or_intersection_type(
1705        p,
1706        UnionOrIntersection::Union,
1707        parse_ts_intersection_type_or_higher,
1708        &P::Token::BIT_OR,
1709    )
1710}
1711
1712/// `tsParseIntersectionTypeOrHigher`
1713fn parse_ts_intersection_type_or_higher<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
1714    trace_cur!(p, parse_ts_intersection_type_or_higher);
1715
1716    debug_assert!(p.input().syntax().typescript());
1717
1718    parse_ts_union_or_intersection_type(
1719        p,
1720        UnionOrIntersection::Intersection,
1721        parse_ts_type_operator_or_higher,
1722        &P::Token::BIT_AND,
1723    )
1724}
1725
1726/// `tsParseTypeOperatorOrHigher`
1727fn parse_ts_type_operator_or_higher<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
1728    trace_cur!(p, parse_ts_type_operator_or_higher);
1729    debug_assert!(p.input().syntax().typescript());
1730
1731    let operator = if p.input().is(&P::Token::KEYOF) {
1732        Some(TsTypeOperatorOp::KeyOf)
1733    } else if p.input().is(&P::Token::UNIQUE) {
1734        Some(TsTypeOperatorOp::Unique)
1735    } else if p.input().is(&P::Token::READONLY) {
1736        Some(TsTypeOperatorOp::ReadOnly)
1737    } else {
1738        None
1739    };
1740
1741    match operator {
1742        Some(operator) => parse_ts_type_operator(p, operator)
1743            .map(TsType::from)
1744            .map(Box::new),
1745        None => {
1746            trace_cur!(p, parse_ts_type_operator_or_higher__not_operator);
1747
1748            if p.input().is(&P::Token::INFER) {
1749                parse_ts_infer_type(p).map(TsType::from).map(Box::new)
1750            } else {
1751                let readonly = parse_ts_modifier(p, &["readonly"], false)?.is_some();
1752                parse_ts_array_type_or_higher(p, readonly)
1753            }
1754        }
1755    }
1756}
1757
1758/// `tsParseTypeOperator`
1759fn parse_ts_type_operator<'a, P: Parser<'a>>(
1760    p: &mut P,
1761    op: TsTypeOperatorOp,
1762) -> PResult<TsTypeOperator> {
1763    debug_assert!(p.input().syntax().typescript());
1764
1765    let start = p.cur_pos();
1766    match op {
1767        TsTypeOperatorOp::Unique => expect!(p, &P::Token::UNIQUE),
1768        TsTypeOperatorOp::KeyOf => expect!(p, &P::Token::KEYOF),
1769        TsTypeOperatorOp::ReadOnly => expect!(p, &P::Token::READONLY),
1770    }
1771
1772    let type_ann = parse_ts_type_operator_or_higher(p)?;
1773    Ok(TsTypeOperator {
1774        span: p.span(start),
1775        op,
1776        type_ann,
1777    })
1778}
1779
1780/// `tsParseInferType`
1781fn parse_ts_infer_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsInferType> {
1782    debug_assert!(p.input().syntax().typescript());
1783
1784    let start = p.cur_pos();
1785    expect!(p, &P::Token::INFER);
1786    let type_param_name = parse_ident_name(p)?;
1787    let constraint = try_parse_ts(p, |p| {
1788        expect!(p, &P::Token::EXTENDS);
1789        let constraint = parse_ts_non_conditional_type(p);
1790        if p.ctx().contains(Context::DisallowConditionalTypes) || !p.input().is(&P::Token::QUESTION)
1791        {
1792            constraint.map(Some)
1793        } else {
1794            Ok(None)
1795        }
1796    });
1797    let type_param = TsTypeParam {
1798        span: type_param_name.span(),
1799        name: type_param_name.into(),
1800        is_in: false,
1801        is_out: false,
1802        is_const: false,
1803        constraint,
1804        default: None,
1805    };
1806    Ok(TsInferType {
1807        span: p.span(start),
1808        type_param,
1809    })
1810}
1811
1812/// `tsParseNonConditionalType`
1813fn parse_ts_non_conditional_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
1814    trace_cur!(p, parse_ts_non_conditional_type);
1815
1816    debug_assert!(p.input().syntax().typescript());
1817
1818    if is_ts_start_of_fn_type(p) {
1819        return parse_ts_fn_or_constructor_type(p, true)
1820            .map(TsType::from)
1821            .map(Box::new);
1822    }
1823    if (p.input().is(&P::Token::ABSTRACT) && peek!(p).is_some_and(|cur| cur.is_new()))
1824        || p.input().is(&P::Token::NEW)
1825    {
1826        // As in `new () => Date`
1827        return parse_ts_fn_or_constructor_type(p, false)
1828            .map(TsType::from)
1829            .map(Box::new);
1830    }
1831
1832    parse_ts_union_type_or_higher(p)
1833}
1834
1835/// `tsParseArrayTypeOrHigher`
1836fn parse_ts_array_type_or_higher<'a, P: Parser<'a>>(
1837    p: &mut P,
1838    readonly: bool,
1839) -> PResult<Box<TsType>> {
1840    trace_cur!(p, parse_ts_array_type_or_higher);
1841    debug_assert!(p.input().syntax().typescript());
1842
1843    let mut ty = parse_ts_non_array_type(p)?;
1844
1845    while !p.input().had_line_break_before_cur() && p.input_mut().eat(&P::Token::LBRACKET) {
1846        if p.input_mut().eat(&P::Token::RBRACKET) {
1847            ty = Box::new(TsType::TsArrayType(TsArrayType {
1848                span: p.span(ty.span_lo()),
1849                elem_type: ty,
1850            }));
1851        } else {
1852            let index_type = parse_ts_type(p)?;
1853            expect!(p, &P::Token::RBRACKET);
1854            ty = Box::new(TsType::TsIndexedAccessType(TsIndexedAccessType {
1855                span: p.span(ty.span_lo()),
1856                readonly,
1857                obj_type: ty,
1858                index_type,
1859            }))
1860        }
1861    }
1862
1863    Ok(ty)
1864}
1865
1866/// Be sure to be in a type context before calling p.
1867///
1868/// `tsParseType`
1869pub fn parse_ts_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
1870    trace_cur!(p, parse_ts_type);
1871
1872    debug_assert!(p.input().syntax().typescript());
1873
1874    // Need to set `state.inType` so that we don't parse JSX in a type context.
1875    debug_assert!(p.ctx().contains(Context::InType));
1876
1877    let start = p.cur_pos();
1878
1879    p.do_outside_of_context(Context::DisallowConditionalTypes, |p| {
1880        let ty = parse_ts_non_conditional_type(p)?;
1881        if p.input().had_line_break_before_cur() || !p.input_mut().eat(&P::Token::EXTENDS) {
1882            return Ok(ty);
1883        }
1884
1885        let check_type = ty;
1886        let extends_type = p.do_inside_of_context(
1887            Context::DisallowConditionalTypes,
1888            parse_ts_non_conditional_type,
1889        )?;
1890
1891        expect!(p, &P::Token::QUESTION);
1892
1893        let true_type = parse_ts_type(p)?;
1894
1895        expect!(p, &P::Token::COLON);
1896
1897        let false_type = parse_ts_type(p)?;
1898
1899        Ok(Box::new(TsType::TsConditionalType(TsConditionalType {
1900            span: p.span(start),
1901            check_type,
1902            extends_type,
1903            true_type,
1904            false_type,
1905        })))
1906    })
1907}
1908
1909/// `parsePropertyName` in babel.
1910///
1911/// Returns `(computed, key)`.
1912fn parse_ts_property_name<'a, P: Parser<'a>>(p: &mut P) -> PResult<(bool, Box<Expr>)> {
1913    let (computed, key) = if p.input_mut().eat(&P::Token::LBRACKET) {
1914        let key = parse_assignment_expr(p)?;
1915        expect!(p, &P::Token::RBRACKET);
1916        (true, key)
1917    } else {
1918        p.do_inside_of_context(Context::InPropertyName, |p| {
1919            // We check if it's valid for it to be a private name when we push it.
1920            let cur = p.input().cur();
1921
1922            let key = if cur.is_num() || cur.is_str() {
1923                parse_new_expr(p)
1924            } else if cur.is_error() {
1925                let err = p.input_mut().expect_error_token_and_bump();
1926                return Err(err);
1927            } else {
1928                parse_maybe_private_name(p).map(|e| match e {
1929                    Either::Left(e) => {
1930                        p.emit_err(e.span(), SyntaxError::PrivateNameInInterface);
1931
1932                        e.into()
1933                    }
1934                    Either::Right(e) => e.into(),
1935                })
1936            };
1937            key.map(|key| (false, key))
1938        })?
1939    };
1940
1941    Ok((computed, key))
1942}
1943
1944/// `tsParsePropertyOrMethodSignature`
1945fn parse_ts_property_or_method_signature<'a, P: Parser<'a>>(
1946    p: &mut P,
1947    start: BytePos,
1948    readonly: bool,
1949) -> PResult<Either<TsPropertySignature, TsMethodSignature>> {
1950    debug_assert!(p.input().syntax().typescript());
1951
1952    let (computed, key) = parse_ts_property_name(p)?;
1953
1954    let optional = p.input_mut().eat(&P::Token::QUESTION);
1955
1956    let cur = p.input().cur();
1957    if cur.is_lparen() || cur.is_less() {
1958        if readonly {
1959            syntax_error!(p, SyntaxError::ReadOnlyMethod)
1960        }
1961
1962        let type_params = try_parse_ts_type_params(p, false, true)?;
1963        expect!(p, &P::Token::LPAREN);
1964        let params = parse_ts_binding_list_for_signature(p)?;
1965        let type_ann = if p.input().is(&P::Token::COLON) {
1966            parse_ts_type_or_type_predicate_ann(p, &P::Token::COLON).map(Some)?
1967        } else {
1968            None
1969        };
1970        // -----
1971
1972        parse_ts_type_member_semicolon(p)?;
1973        Ok(Either::Right(TsMethodSignature {
1974            span: p.span(start),
1975            computed,
1976            key,
1977            optional,
1978            type_params,
1979            params,
1980            type_ann,
1981        }))
1982    } else {
1983        let type_ann = try_parse_ts_type_ann(p)?;
1984
1985        parse_ts_type_member_semicolon(p)?;
1986        Ok(Either::Left(TsPropertySignature {
1987            span: p.span(start),
1988            computed,
1989            readonly,
1990            key,
1991            optional,
1992            type_ann,
1993        }))
1994    }
1995}
1996
1997/// `tsParseTypeMember`
1998fn parse_ts_type_member<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTypeElement> {
1999    debug_assert!(p.input().syntax().typescript());
2000
2001    fn into_type_elem(e: Either<TsCallSignatureDecl, TsConstructSignatureDecl>) -> TsTypeElement {
2002        match e {
2003            Either::Left(e) => e.into(),
2004            Either::Right(e) => e.into(),
2005        }
2006    }
2007    let cur = p.input().cur();
2008    if cur.is_lparen() || cur.is_less() {
2009        return parse_ts_signature_member(p, SignatureParsingMode::TSCallSignatureDeclaration)
2010            .map(into_type_elem);
2011    }
2012    if p.input().is(&P::Token::NEW) && ts_look_ahead(p, is_ts_start_of_construct_signature) {
2013        return parse_ts_signature_member(p, SignatureParsingMode::TSConstructSignatureDeclaration)
2014            .map(into_type_elem);
2015    }
2016    // Instead of fullStart, we create a node here.
2017    let start = p.cur_pos();
2018    let readonly = parse_ts_modifier(p, &["readonly"], false)?.is_some();
2019
2020    let idx = try_parse_ts_index_signature(p, start, readonly, false)?;
2021    if let Some(idx) = idx {
2022        return Ok(idx.into());
2023    }
2024
2025    if let Some(v) = try_parse_ts(p, |p| {
2026        let start = p.input().cur_pos();
2027
2028        if readonly {
2029            syntax_error!(p, SyntaxError::GetterSetterCannotBeReadonly)
2030        }
2031
2032        let is_get = if p.input_mut().eat(&P::Token::GET) {
2033            true
2034        } else {
2035            expect!(p, &P::Token::SET);
2036            false
2037        };
2038
2039        let (computed, key) = parse_ts_property_name(p)?;
2040
2041        if is_get {
2042            expect!(p, &P::Token::LPAREN);
2043            expect!(p, &P::Token::RPAREN);
2044            let type_ann = try_parse_ts_type_ann(p)?;
2045
2046            parse_ts_type_member_semicolon(p)?;
2047
2048            Ok(Some(TsTypeElement::TsGetterSignature(TsGetterSignature {
2049                span: p.span(start),
2050                key,
2051                computed,
2052                type_ann,
2053            })))
2054        } else {
2055            expect!(p, &P::Token::LPAREN);
2056            let params = parse_ts_binding_list_for_signature(p)?;
2057            if params.is_empty() {
2058                syntax_error!(p, SyntaxError::SetterParamRequired)
2059            }
2060            let param = params.into_iter().next().unwrap();
2061
2062            parse_ts_type_member_semicolon(p)?;
2063
2064            Ok(Some(TsTypeElement::TsSetterSignature(TsSetterSignature {
2065                span: p.span(start),
2066                key,
2067                computed,
2068                param,
2069            })))
2070        }
2071    }) {
2072        return Ok(v);
2073    }
2074
2075    parse_ts_property_or_method_signature(p, start, readonly).map(|e| match e {
2076        Either::Left(e) => e.into(),
2077        Either::Right(e) => e.into(),
2078    })
2079}
2080
2081/// `tsParseObjectTypeMembers`
2082fn parse_ts_object_type_members<'a, P: Parser<'a>>(p: &mut P) -> PResult<Vec<TsTypeElement>> {
2083    debug_assert!(p.input().syntax().typescript());
2084
2085    expect!(p, &P::Token::LBRACE);
2086    let members = parse_ts_list(p, ParsingContext::TypeMembers, |p| parse_ts_type_member(p))?;
2087    expect!(p, &P::Token::RBRACE);
2088    Ok(members)
2089}
2090
2091/// `tsParseTypeLiteral`
2092pub fn parse_ts_type_lit<'a>(p: &mut impl Parser<'a>) -> PResult<TsTypeLit> {
2093    debug_assert!(p.input().syntax().typescript());
2094
2095    let start = p.cur_pos();
2096    let members = parse_ts_object_type_members(p)?;
2097    Ok(TsTypeLit {
2098        span: p.span(start),
2099        members,
2100    })
2101}
2102
2103/// `tsParseInterfaceDeclaration`
2104pub fn parse_ts_interface_decl<'a, P: Parser<'a>>(
2105    p: &mut P,
2106    start: BytePos,
2107) -> PResult<Box<TsInterfaceDecl>> {
2108    debug_assert!(p.input().syntax().typescript());
2109
2110    let id = parse_ident_name(p)?;
2111    match &*id.sym {
2112        "string" | "null" | "number" | "object" | "any" | "unknown" | "boolean" | "bigint"
2113        | "symbol" | "void" | "never" | "intrinsic" => {
2114            p.emit_err(id.span, SyntaxError::TS2427);
2115        }
2116        _ => {}
2117    }
2118
2119    let type_params = try_parse_ts_type_params(p, true, false)?;
2120
2121    let extends = if p.input_mut().eat(&P::Token::EXTENDS) {
2122        parse_ts_heritage_clause(p)?
2123    } else {
2124        Vec::new()
2125    };
2126
2127    // Recover from
2128    //
2129    //     interface I extends A extends B {}
2130    if p.input().is(&P::Token::EXTENDS) {
2131        p.emit_err(p.input().cur_span(), SyntaxError::TS1172);
2132
2133        while !p.input().cur().is_eof() && !p.input().is(&P::Token::LBRACE) {
2134            p.bump();
2135        }
2136    }
2137
2138    let body_start = p.cur_pos();
2139    let body = p.in_type(parse_ts_object_type_members)?;
2140    let body = TsInterfaceBody {
2141        span: p.span(body_start),
2142        body,
2143    };
2144    Ok(Box::new(TsInterfaceDecl {
2145        span: p.span(start),
2146        declare: false,
2147        id: id.into(),
2148        type_params,
2149        extends,
2150        body,
2151    }))
2152}
2153
2154/// `tsParseTypeAssertion`
2155pub fn parse_ts_type_assertion<'a, P: Parser<'a>>(
2156    p: &mut P,
2157    start: BytePos,
2158) -> PResult<TsTypeAssertion> {
2159    debug_assert!(p.input().syntax().typescript());
2160
2161    if p.input().syntax().disallow_ambiguous_jsx_like() {
2162        p.emit_err(p.span(start), SyntaxError::ReservedTypeAssertion);
2163    }
2164
2165    // Not actually necessary to set state.inType because we never reach here if JSX
2166    // plugin is enabled, but need `tsInType` to satisfy the assertion in
2167    // `tsParseType`.
2168    let type_ann = p.in_type(parse_ts_type)?;
2169    expect!(p, &P::Token::GREATER);
2170    let expr = p.parse_unary_expr()?;
2171    Ok(TsTypeAssertion {
2172        span: p.span(start),
2173        type_ann,
2174        expr,
2175    })
2176}
2177
2178/// `tsParseImportType`
2179fn parse_ts_import_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsImportType> {
2180    let start = p.cur_pos();
2181    p.assert_and_bump(&P::Token::IMPORT);
2182
2183    expect!(p, &P::Token::LPAREN);
2184
2185    let cur = p.input().cur();
2186
2187    let arg = if cur.is_str() {
2188        parse_str_lit(p)
2189    } else if cur.is_error() {
2190        let err = p.input_mut().expect_error_token_and_bump();
2191        return Err(err);
2192    } else {
2193        let arg_span = p.input().cur_span();
2194        p.bump();
2195        p.emit_err(arg_span, SyntaxError::TS1141);
2196        Str {
2197            span: arg_span,
2198            value: atom!(""),
2199            raw: Some(atom!("\"\"")),
2200        }
2201    };
2202
2203    // the "assert" keyword is deprecated and this syntax is niche, so
2204    // don't support it
2205    let attributes = if p.input_mut().eat(&P::Token::COMMA)
2206        && p.input().syntax().import_attributes()
2207        && p.input().is(&P::Token::LBRACE)
2208    {
2209        Some(parse_ts_call_options(p)?)
2210    } else {
2211        None
2212    };
2213
2214    expect!(p, &P::Token::RPAREN);
2215
2216    let qualifier = if p.input_mut().eat(&P::Token::DOT) {
2217        parse_ts_entity_name(p, false).map(Some)?
2218    } else {
2219        None
2220    };
2221
2222    let type_args = if p.input().is(&P::Token::LESS) {
2223        let ret = p.do_outside_of_context(Context::ShouldNotLexLtOrGtAsType, parse_ts_type_args)?;
2224        p.assert_and_bump(&P::Token::GREATER);
2225        Some(ret)
2226    } else {
2227        None
2228    };
2229
2230    Ok(TsImportType {
2231        span: p.span(start),
2232        arg,
2233        qualifier,
2234        type_args,
2235        attributes,
2236    })
2237}
2238
2239fn parse_ts_call_options<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsImportCallOptions> {
2240    debug_assert!(p.input().syntax().typescript());
2241    let start = p.cur_pos();
2242    p.assert_and_bump(&P::Token::LBRACE);
2243
2244    expect!(p, &P::Token::WITH);
2245    expect!(p, &P::Token::COLON);
2246
2247    let value = match parse_object_expr(p)? {
2248        Expr::Object(v) => v,
2249        _ => unreachable!(),
2250    };
2251    p.input_mut().eat(&P::Token::COMMA);
2252    expect!(p, &P::Token::RBRACE);
2253    Ok(TsImportCallOptions {
2254        span: p.span(start),
2255        with: Box::new(value),
2256    })
2257}
2258
2259/// `tsParseTypeQuery`
2260fn parse_ts_type_query<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTypeQuery> {
2261    debug_assert!(p.input().syntax().typescript());
2262
2263    let start = p.cur_pos();
2264    expect!(p, &P::Token::TYPEOF);
2265    let expr_name = if p.input().is(&P::Token::IMPORT) {
2266        parse_ts_import_type(p).map(From::from)?
2267    } else {
2268        parse_ts_entity_name(
2269            p, // allow_reserved_word
2270            true,
2271        )
2272        .map(From::from)?
2273    };
2274
2275    let type_args = if !p.input().had_line_break_before_cur() && p.input().is(&P::Token::LESS) {
2276        let ret = p.do_outside_of_context(Context::ShouldNotLexLtOrGtAsType, parse_ts_type_args)?;
2277        p.assert_and_bump(&P::Token::GREATER);
2278        Some(ret)
2279    } else {
2280        None
2281    };
2282
2283    Ok(TsTypeQuery {
2284        span: p.span(start),
2285        expr_name,
2286        type_args,
2287    })
2288}
2289
2290/// `tsParseModuleBlock`
2291fn parse_ts_module_block<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsModuleBlock> {
2292    trace_cur!(p, parse_ts_module_block);
2293
2294    debug_assert!(p.input().syntax().typescript());
2295
2296    let start = p.cur_pos();
2297    expect!(p, &P::Token::LBRACE);
2298    let body = p.do_inside_of_context(Context::TsModuleBlock, |p| {
2299        p.do_outside_of_context(Context::TopLevel, |p| {
2300            parse_module_item_block_body(p, false, Some(&P::Token::RBRACE))
2301        })
2302    })?;
2303
2304    Ok(TsModuleBlock {
2305        span: p.span(start),
2306        body,
2307    })
2308}
2309
2310/// `tsParseModuleOrNamespaceDeclaration`
2311fn parse_ts_module_or_ns_decl<'a, P: Parser<'a>>(
2312    p: &mut P,
2313    start: BytePos,
2314    namespace: bool,
2315) -> PResult<Box<TsModuleDecl>> {
2316    debug_assert!(p.input().syntax().typescript());
2317
2318    let id = parse_ident_name(p)?;
2319    let body: TsNamespaceBody = if p.input_mut().eat(&P::Token::DOT) {
2320        let inner_start = p.cur_pos();
2321        let inner = parse_ts_module_or_ns_decl(p, inner_start, namespace)?;
2322        let inner = TsNamespaceDecl {
2323            span: inner.span,
2324            id: match inner.id {
2325                TsModuleName::Ident(i) => i,
2326                _ => unreachable!(),
2327            },
2328            body: Box::new(inner.body.unwrap()),
2329            declare: inner.declare,
2330            global: inner.global,
2331        };
2332        inner.into()
2333    } else {
2334        parse_ts_module_block(p).map(From::from)?
2335    };
2336
2337    Ok(Box::new(TsModuleDecl {
2338        span: p.span(start),
2339        declare: false,
2340        id: TsModuleName::Ident(id.into()),
2341        body: Some(body),
2342        global: false,
2343        namespace,
2344    }))
2345}
2346
2347/// `tsParseAmbientExternalModuleDeclaration`
2348fn parse_ts_ambient_external_module_decl<'a, P: Parser<'a>>(
2349    p: &mut P,
2350    start: BytePos,
2351) -> PResult<Box<TsModuleDecl>> {
2352    debug_assert!(p.input().syntax().typescript());
2353
2354    let (global, id) = if p.input().is(&P::Token::GLOBAL) {
2355        let id = parse_ident_name(p)?;
2356        (true, TsModuleName::Ident(id.into()))
2357    } else if p.input().cur().is_str() {
2358        let id = TsModuleName::Str(parse_str_lit(p));
2359        (false, id)
2360    } else {
2361        unexpected!(p, "global or a string literal");
2362    };
2363
2364    let body = if p.input().is(&P::Token::LBRACE) {
2365        Some(parse_ts_module_block(p).map(TsNamespaceBody::from)?)
2366    } else {
2367        p.expect_general_semi()?;
2368        None
2369    };
2370
2371    Ok(Box::new(TsModuleDecl {
2372        span: p.span(start),
2373        declare: false,
2374        id,
2375        global,
2376        body,
2377        namespace: false,
2378    }))
2379}
2380
2381/// `tsParseNonArrayType`
2382fn parse_ts_non_array_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
2383    if !cfg!(feature = "typescript") {
2384        unreachable!()
2385    }
2386    trace_cur!(p, parse_ts_non_array_type);
2387    debug_assert!(p.input().syntax().typescript());
2388
2389    let start = p.cur_pos();
2390
2391    let cur = p.input().cur();
2392    if cur.is_known_ident()
2393        || cur.is_unknown_ident()
2394        || cur.is_void()
2395        || cur.is_yield()
2396        || cur.is_null()
2397        || cur.is_await()
2398        || cur.is_break()
2399    {
2400        if p.input().is(&P::Token::ASSERTS) && peek!(p).is_some_and(|peek| peek.is_this()) {
2401            p.bump();
2402            let this_keyword = parse_ts_this_type_node(p)?;
2403            return parse_ts_this_type_predicate(p, start, true, this_keyword)
2404                .map(TsType::from)
2405                .map(Box::new);
2406        }
2407        let kind = if p.input().is(&P::Token::VOID) {
2408            Some(TsKeywordTypeKind::TsVoidKeyword)
2409        } else if p.input().is(&P::Token::NULL) {
2410            Some(TsKeywordTypeKind::TsNullKeyword)
2411        } else if p.input().is(&P::Token::ANY) {
2412            Some(TsKeywordTypeKind::TsAnyKeyword)
2413        } else if p.input().is(&P::Token::BOOLEAN) {
2414            Some(TsKeywordTypeKind::TsBooleanKeyword)
2415        } else if p.input().is(&P::Token::BIGINT) {
2416            Some(TsKeywordTypeKind::TsBigIntKeyword)
2417        } else if p.input().is(&P::Token::NEVER) {
2418            Some(TsKeywordTypeKind::TsNeverKeyword)
2419        } else if p.input().is(&P::Token::NUMBER) {
2420            Some(TsKeywordTypeKind::TsNumberKeyword)
2421        } else if p.input().is(&P::Token::OBJECT) {
2422            Some(TsKeywordTypeKind::TsObjectKeyword)
2423        } else if p.input().is(&P::Token::STRING) {
2424            Some(TsKeywordTypeKind::TsStringKeyword)
2425        } else if p.input().is(&P::Token::SYMBOL) {
2426            Some(TsKeywordTypeKind::TsSymbolKeyword)
2427        } else if p.input().is(&P::Token::UNKNOWN) {
2428            Some(TsKeywordTypeKind::TsUnknownKeyword)
2429        } else if p.input().is(&P::Token::UNDEFINED) {
2430            Some(TsKeywordTypeKind::TsUndefinedKeyword)
2431        } else if p.input().is(&P::Token::INTRINSIC) {
2432            Some(TsKeywordTypeKind::TsIntrinsicKeyword)
2433        } else {
2434            None
2435        };
2436
2437        let peeked_is_dot = peek!(p).is_some_and(|cur| cur.is_dot());
2438
2439        match kind {
2440            Some(kind) if !peeked_is_dot => {
2441                p.bump();
2442                return Ok(Box::new(TsType::TsKeywordType(TsKeywordType {
2443                    span: p.span(start),
2444                    kind,
2445                })));
2446            }
2447            _ => {
2448                return parse_ts_type_ref(p).map(TsType::from).map(Box::new);
2449            }
2450        }
2451    } else if cur.is_bigint()
2452        || cur.is_str()
2453        || cur.is_num()
2454        || cur.is_true()
2455        || cur.is_false()
2456        || cur.is_backquote()
2457    {
2458        return parse_ts_lit_type_node(p).map(TsType::from).map(Box::new);
2459    } else if cur.is_no_substitution_template_literal() || cur.is_template_head() {
2460        return p.parse_tagged_tpl_ty().map(TsType::from).map(Box::new);
2461    } else if cur.is_minus() {
2462        let start = p.cur_pos();
2463
2464        p.bump();
2465
2466        let cur = p.input().cur();
2467        if !(cur.is_num() || cur.is_bigint()) {
2468            unexpected!(p, "numeric literal or bigint literal")
2469        }
2470
2471        let lit = parse_lit(p)?;
2472        let lit = match lit {
2473            Lit::Num(Number { span, value, raw }) => {
2474                let mut new_raw = String::from("-");
2475
2476                match raw {
2477                    Some(raw) => {
2478                        new_raw.push_str(&raw);
2479                    }
2480                    _ => {
2481                        write!(new_raw, "{value}").unwrap();
2482                    }
2483                };
2484
2485                TsLit::Number(Number {
2486                    span,
2487                    value: -value,
2488                    raw: Some(new_raw.into()),
2489                })
2490            }
2491            Lit::BigInt(BigInt { span, value, raw }) => {
2492                let mut new_raw = String::from("-");
2493
2494                match raw {
2495                    Some(raw) => {
2496                        new_raw.push_str(&raw);
2497                    }
2498                    _ => {
2499                        write!(new_raw, "{value}").unwrap();
2500                    }
2501                };
2502
2503                TsLit::BigInt(BigInt {
2504                    span,
2505                    value: Box::new(-*value),
2506                    raw: Some(new_raw.into()),
2507                })
2508            }
2509            _ => unreachable!(),
2510        };
2511
2512        return Ok(Box::new(TsType::TsLitType(TsLitType {
2513            span: p.span(start),
2514            lit,
2515        })));
2516    } else if cur.is_import() {
2517        return parse_ts_import_type(p).map(TsType::from).map(Box::new);
2518    } else if cur.is_this() {
2519        let start = p.cur_pos();
2520        let this_keyword = parse_ts_this_type_node(p)?;
2521        return if !p.input().had_line_break_before_cur() && p.input().is(&P::Token::IS) {
2522            parse_ts_this_type_predicate(p, start, false, this_keyword)
2523                .map(TsType::from)
2524                .map(Box::new)
2525        } else {
2526            Ok(Box::new(TsType::TsThisType(this_keyword)))
2527        };
2528    } else if cur.is_typeof() {
2529        return parse_ts_type_query(p).map(TsType::from).map(Box::new);
2530    } else if cur.is_lbrace() {
2531        return if ts_look_ahead(p, is_ts_start_of_mapped_type) {
2532            parse_ts_mapped_type(p).map(TsType::from).map(Box::new)
2533        } else {
2534            parse_ts_type_lit(p).map(TsType::from).map(Box::new)
2535        };
2536    } else if cur.is_lbracket() {
2537        return parse_ts_tuple_type(p).map(TsType::from).map(Box::new);
2538    } else if cur.is_lparen() {
2539        return parse_ts_parenthesized_type(p)
2540            .map(TsType::from)
2541            .map(Box::new);
2542    }
2543
2544    //   switch (p.state.type) {
2545    //   }
2546
2547    unexpected!(
2548        p,
2549        "an identifier, void, yield, null, await, break, a string literal, a numeric literal, \
2550         true, false, `, -, import, this, typeof, {, [, ("
2551    )
2552}
2553
2554/// `tsParseExpressionStatement`
2555pub fn parse_ts_expr_stmt<'a, P: Parser<'a>>(
2556    p: &mut P,
2557    decorators: Vec<Decorator>,
2558    expr: Ident,
2559) -> PResult<Option<Decl>> {
2560    if !cfg!(feature = "typescript") {
2561        return Ok(Default::default());
2562    }
2563
2564    let start = expr.span_lo();
2565
2566    match &*expr.sym {
2567        "declare" => {
2568            let decl = try_parse_ts_declare(p, start, decorators)?;
2569            if let Some(decl) = decl {
2570                Ok(Some(make_decl_declare(decl)))
2571            } else {
2572                Ok(None)
2573            }
2574        }
2575        "global" => {
2576            // `global { }` (with no `declare`) may appear inside an ambient module
2577            // declaration.
2578            // Would like to use tsParseAmbientExternalModuleDeclaration here, but already
2579            // ran past "global".
2580            if p.input().is(&P::Token::LBRACE) {
2581                let global = true;
2582                let id = TsModuleName::Ident(expr);
2583                let body = parse_ts_module_block(p)
2584                    .map(TsNamespaceBody::from)
2585                    .map(Some)?;
2586                Ok(Some(
2587                    TsModuleDecl {
2588                        span: p.span(start),
2589                        global,
2590                        declare: false,
2591                        namespace: false,
2592                        id,
2593                        body,
2594                    }
2595                    .into(),
2596                ))
2597            } else {
2598                Ok(None)
2599            }
2600        }
2601        _ => parse_ts_decl(p, start, decorators, expr.sym, /* next */ false),
2602    }
2603}
2604
2605/// `tsTryParseDeclare`
2606pub fn try_parse_ts_declare<'a, P: Parser<'a>>(
2607    p: &mut P,
2608    start: BytePos,
2609    decorators: Vec<Decorator>,
2610) -> PResult<Option<Decl>> {
2611    if !p.syntax().typescript() {
2612        return Ok(None);
2613    }
2614
2615    if p.ctx()
2616        .contains(Context::InDeclare | Context::TsModuleBlock)
2617    {
2618        let span_of_declare = p.span(start);
2619        p.emit_err(span_of_declare, SyntaxError::TS1038);
2620    }
2621
2622    let declare_start = start;
2623    p.do_inside_of_context(Context::InDeclare, |p| {
2624        if p.input().is(&P::Token::FUNCTION) {
2625            return parse_fn_decl(p, decorators)
2626                .map(|decl| match decl {
2627                    Decl::Fn(f) => FnDecl {
2628                        declare: true,
2629                        function: Box::new(Function {
2630                            span: Span {
2631                                lo: declare_start,
2632                                ..f.function.span
2633                            },
2634                            ..*f.function
2635                        }),
2636                        ..f
2637                    }
2638                    .into(),
2639                    _ => decl,
2640                })
2641                .map(Some);
2642        }
2643
2644        if p.input().is(&P::Token::CLASS) {
2645            return parse_class_decl(p, start, start, decorators, false)
2646                .map(|decl| match decl {
2647                    Decl::Class(c) => ClassDecl {
2648                        declare: true,
2649                        class: Box::new(Class {
2650                            span: Span {
2651                                lo: declare_start,
2652                                ..c.class.span
2653                            },
2654                            ..*c.class
2655                        }),
2656                        ..c
2657                    }
2658                    .into(),
2659                    _ => decl,
2660                })
2661                .map(Some);
2662        }
2663
2664        if p.input().is(&P::Token::CONST) && peek!(p).is_some_and(|peek| peek.is_enum()) {
2665            p.assert_and_bump(&P::Token::CONST);
2666            p.assert_and_bump(&P::Token::ENUM);
2667
2668            return parse_ts_enum_decl(p, start, /* is_const */ true)
2669                .map(|decl| TsEnumDecl {
2670                    declare: true,
2671                    span: Span {
2672                        lo: declare_start,
2673                        ..decl.span
2674                    },
2675                    ..*decl
2676                })
2677                .map(Box::new)
2678                .map(From::from)
2679                .map(Some);
2680        }
2681
2682        let cur = p.input().cur();
2683        if cur.is_const() || cur.is_var() || cur.is_let() {
2684            return parse_var_stmt(p, false)
2685                .map(|decl| VarDecl {
2686                    declare: true,
2687                    span: Span {
2688                        lo: declare_start,
2689                        ..decl.span
2690                    },
2691                    ..*decl
2692                })
2693                .map(Box::new)
2694                .map(From::from)
2695                .map(Some);
2696        }
2697
2698        if p.input().is(&P::Token::GLOBAL) {
2699            return parse_ts_ambient_external_module_decl(p, start)
2700                .map(Decl::from)
2701                .map(make_decl_declare)
2702                .map(Some);
2703        } else if p.input().cur().is_word() {
2704            let value = p
2705                .input_mut()
2706                .cur()
2707                .clone()
2708                .take_word(p.input_mut())
2709                .unwrap();
2710            return parse_ts_decl(p, start, decorators, value, /* next */ true)
2711                .map(|v| v.map(make_decl_declare));
2712        }
2713
2714        Ok(None)
2715    })
2716}
2717
2718/// `tsTryParseExportDeclaration`
2719///
2720/// Note: this won't be called unless the keyword is allowed in
2721/// `shouldParseExportDeclaration`.
2722pub fn try_parse_ts_export_decl<'a, P: Parser<'a>>(
2723    p: &mut P,
2724    decorators: Vec<Decorator>,
2725    value: Atom,
2726) -> Option<Decl> {
2727    if !cfg!(feature = "typescript") {
2728        return None;
2729    }
2730
2731    try_parse_ts(p, |p| {
2732        let start = p.cur_pos();
2733        let opt = parse_ts_decl(p, start, decorators, value, true)?;
2734        Ok(opt)
2735    })
2736}
2737
2738/// Common to tsTryParseDeclare, tsTryParseExportDeclaration, and
2739/// tsParseExpressionStatement.
2740///
2741/// `tsParseDeclaration`
2742fn parse_ts_decl<'a, P: Parser<'a>>(
2743    p: &mut P,
2744    start: BytePos,
2745    decorators: Vec<Decorator>,
2746    value: Atom,
2747    next: bool,
2748) -> PResult<Option<Decl>> {
2749    if !cfg!(feature = "typescript") {
2750        return Ok(Default::default());
2751    }
2752
2753    match &*value {
2754        "abstract" => {
2755            if next || (p.input().is(&P::Token::CLASS) && !p.input().had_line_break_before_cur()) {
2756                if next {
2757                    p.bump();
2758                }
2759                return Ok(Some(parse_class_decl(p, start, start, decorators, true)?));
2760            }
2761        }
2762
2763        "enum" => {
2764            if next || p.is_ident_ref() {
2765                if next {
2766                    p.bump();
2767                }
2768                return parse_ts_enum_decl(p, start, /* is_const */ false)
2769                    .map(From::from)
2770                    .map(Some);
2771            }
2772        }
2773
2774        "interface" => {
2775            if next || (p.is_ident_ref()) {
2776                if next {
2777                    p.bump();
2778                }
2779
2780                return parse_ts_interface_decl(p, start).map(From::from).map(Some);
2781            }
2782        }
2783
2784        "module" if !p.input().had_line_break_before_cur() => {
2785            if next {
2786                p.bump();
2787            }
2788
2789            let cur = p.input().cur();
2790            if cur.is_str() {
2791                return parse_ts_ambient_external_module_decl(p, start)
2792                    .map(From::from)
2793                    .map(Some);
2794            } else if cur.is_error() {
2795                let err = p.input_mut().expect_error_token_and_bump();
2796                return Err(err);
2797            } else if cur.is_eof() {
2798                return Err(eof_error(p));
2799            } else if next || p.is_ident_ref() {
2800                return parse_ts_module_or_ns_decl(p, start, false)
2801                    .map(From::from)
2802                    .map(Some);
2803            }
2804        }
2805
2806        "namespace" => {
2807            if next || p.is_ident_ref() {
2808                if next {
2809                    p.bump();
2810                }
2811                return parse_ts_module_or_ns_decl(p, start, true)
2812                    .map(From::from)
2813                    .map(Some);
2814            }
2815        }
2816
2817        "type" => {
2818            if next || (!p.input().had_line_break_before_cur() && p.is_ident_ref()) {
2819                if next {
2820                    p.bump();
2821                }
2822                return parse_ts_type_alias_decl(p, start).map(From::from).map(Some);
2823            }
2824        }
2825
2826        _ => {}
2827    }
2828
2829    Ok(None)
2830}
2831
2832/// `tsTryParseGenericAsyncArrowFunction`
2833pub fn try_parse_ts_generic_async_arrow_fn<'a, P: Parser<'a>>(
2834    p: &mut P,
2835    start: BytePos,
2836) -> PResult<Option<ArrowExpr>> {
2837    if !cfg!(feature = "typescript") {
2838        return Ok(Default::default());
2839    }
2840
2841    let cur = p.input().cur();
2842    let res = if cur.is_less() || cur.is_jsx_tag_start() {
2843        try_parse_ts(p, |p| {
2844            let type_params = parse_ts_type_params(p, false, false)?;
2845            // Don't use overloaded parseFunctionParams which would look for "<" again.
2846            expect!(p, &P::Token::LPAREN);
2847            let params: Vec<Pat> = parse_formal_params(p)?.into_iter().map(|p| p.pat).collect();
2848            expect!(p, &P::Token::RPAREN);
2849            let return_type = try_parse_ts_type_or_type_predicate_ann(p)?;
2850            expect!(p, &P::Token::ARROW);
2851
2852            Ok(Some((type_params, params, return_type)))
2853        })
2854    } else {
2855        None
2856    };
2857
2858    let (type_params, params, return_type) = match res {
2859        Some(v) => v,
2860        None => return Ok(None),
2861    };
2862
2863    p.do_inside_of_context(Context::InAsync, |p| {
2864        p.do_outside_of_context(Context::InGenerator, |p| {
2865            let is_generator = false;
2866            let is_async = true;
2867            let body = parse_fn_block_or_expr_body(
2868                p,
2869                true,
2870                false,
2871                true,
2872                params.is_simple_parameter_list(),
2873            )?;
2874            Ok(Some(ArrowExpr {
2875                span: p.span(start),
2876                body,
2877                is_async,
2878                is_generator,
2879                type_params: Some(type_params),
2880                params,
2881                return_type,
2882                ..Default::default()
2883            }))
2884        })
2885    })
2886}