Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/swc_ecma_parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,8 @@ pub struct Context {
allow_direct_super: bool,

ignore_else_clause: bool,

disallow_conditional_types: bool,
}

#[cfg(test)]
Expand Down
59 changes: 41 additions & 18 deletions crates/swc_ecma_parser/src/parser/typescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -898,29 +898,43 @@ impl<I: Tokens> Parser<I> {

let start = cur_pos!(self);

let ty = self.parse_ts_non_conditional_type()?;
if self.input.had_line_break_before_cur() || !eat!(self, "extends") {
return Ok(ty);
}
self.with_ctx(Context {
disallow_conditional_types: false,
..self.ctx()
})
.parse_with(|p| {
let ty = p.parse_ts_non_conditional_type()?;
if p.input.had_line_break_before_cur() || !eat!(p, "extends") {
return Ok(ty);
}

let check_type = ty;
let extends_type = self.parse_ts_non_conditional_type()?;
let check_type = ty;
let extends_type = p.parse_ts_non_conditional_type_within_ctx()?;

expect!(self, '?');
expect!(p, '?');

let true_type = self.parse_ts_type()?;
let true_type = p.parse_ts_type()?;

expect!(self, ':');
expect!(p, ':');

let false_type = self.parse_ts_type()?;
let false_type = p.parse_ts_type()?;

Ok(Box::new(TsType::TsConditionalType(TsConditionalType {
span: span!(self, start),
check_type,
extends_type,
true_type,
false_type,
})))
Ok(Box::new(TsType::TsConditionalType(TsConditionalType {
span: span!(p, start),
check_type,
extends_type,
true_type,
false_type,
})))
})
}

fn parse_ts_non_conditional_type_within_ctx(&mut self) -> PResult<Box<TsType>> {
self.with_ctx(Context {
disallow_conditional_types: true,
..self.ctx()
})
.parse_ts_non_conditional_type()
}

/// `tsParseNonConditionalType`
Expand Down Expand Up @@ -2197,12 +2211,21 @@ impl<I: Tokens> Parser<I> {
let start = cur_pos!(self);
expect!(self, "infer");
let type_param_name = self.parse_ident_name()?;
let constraint = self.try_parse_ts(|p| {
expect!(p, "extends");
let constraint = p.parse_ts_non_conditional_type();
if p.ctx().disallow_conditional_types || !is!(p, '?') {
constraint.map(Some)
} else {
Ok(None)
}
});
let type_param = TsTypeParam {
span: type_param_name.span(),
name: type_param_name,
is_in: false,
is_out: false,
constraint: None,
constraint,
default: None,
};
Ok(TsInferType {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
type X1<T extends any[]> =
T extends [infer U extends string] ? ["string", U] :
T extends [infer U extends number] ? ["number", U] :
never;

type X2<T extends (...args: any[]) => void> =
T extends (a: infer U extends string) => void ? ["string", U] :
T extends (a: infer U extends number) => void ? ["number", U] :
never;

type X3<T extends (...args: any[]) => any> =
T extends (...args: any[]) => (infer U extends string) ? ["string", U] :
T extends (...args: any[]) => (infer U extends number) ? ["number", U] :
never;

type X4<T extends new (...args: any[]) => any> =
T extends new (...args: any[]) => (infer U extends { a: string }) ? ["string", U] :
T extends new (...args: any[]) => (infer U extends { a: number }) ? ["number", U] :
never;

type X5<T> =
T extends Promise<infer U extends string> ? ["string", U] :
T extends Promise<infer U extends number> ? ["number", U] :
never;

type X6<T> =
T extends { a: infer U extends string } ? ["string", U] :
T extends { a: infer U extends number } ? ["number", U] :
never;
Loading