mirror of
https://github.com/swc-project/swc.git
synced 2024-11-26 20:36:17 +03:00
feat(es/parser): Support extends
clause to infer
type (#4326)
This commit is contained in:
parent
39dc394933
commit
1c3d1af01c
@ -387,6 +387,8 @@ pub struct Context {
|
|||||||
allow_direct_super: bool,
|
allow_direct_super: bool,
|
||||||
|
|
||||||
ignore_else_clause: bool,
|
ignore_else_clause: bool,
|
||||||
|
|
||||||
|
disallow_conditional_types: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -898,29 +898,43 @@ impl<I: Tokens> Parser<I> {
|
|||||||
|
|
||||||
let start = cur_pos!(self);
|
let start = cur_pos!(self);
|
||||||
|
|
||||||
let ty = self.parse_ts_non_conditional_type()?;
|
self.with_ctx(Context {
|
||||||
if self.input.had_line_break_before_cur() || !eat!(self, "extends") {
|
disallow_conditional_types: false,
|
||||||
return Ok(ty);
|
..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 check_type = ty;
|
||||||
let extends_type = self.parse_ts_non_conditional_type()?;
|
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 {
|
Ok(Box::new(TsType::TsConditionalType(TsConditionalType {
|
||||||
span: span!(self, start),
|
span: span!(p, start),
|
||||||
check_type,
|
check_type,
|
||||||
extends_type,
|
extends_type,
|
||||||
true_type,
|
true_type,
|
||||||
false_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`
|
/// `tsParseNonConditionalType`
|
||||||
@ -2197,12 +2211,21 @@ impl<I: Tokens> Parser<I> {
|
|||||||
let start = cur_pos!(self);
|
let start = cur_pos!(self);
|
||||||
expect!(self, "infer");
|
expect!(self, "infer");
|
||||||
let type_param_name = self.parse_ident_name()?;
|
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 {
|
let type_param = TsTypeParam {
|
||||||
span: type_param_name.span(),
|
span: type_param_name.span(),
|
||||||
name: type_param_name,
|
name: type_param_name,
|
||||||
is_in: false,
|
is_in: false,
|
||||||
is_out: false,
|
is_out: false,
|
||||||
constraint: None,
|
constraint,
|
||||||
default: None,
|
default: None,
|
||||||
};
|
};
|
||||||
Ok(TsInferType {
|
Ok(TsInferType {
|
||||||
|
@ -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;
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,9 @@
|
|||||||
|
type X10<T> = T extends (infer U extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional
|
||||||
|
type X11<T> = T extends ((infer U) extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional
|
||||||
|
type X12<T> = T extends (infer U extends number) ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
|
||||||
|
type X13<T> = T extends infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (conditional types not allowed in 'extends type')
|
||||||
|
type X14<T> = T extends keyof infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (precedence wouldn't have parsed the `?` as part of a type operator)
|
||||||
|
type X15<T> = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional
|
||||||
|
type X16<T> = T extends { [P in infer U extends keyof T]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
|
||||||
|
type X17<T> = T extends { [P in keyof T as infer U extends P ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional
|
||||||
|
type X18<T> = T extends { [P in keyof T as infer U extends P]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`)
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user