mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(codegen): tighten conditional-type and constructor-type whitespace when minifying (#23033)
## What
Batches the remaining low-risk TS-minify whitespace patterns surfaced by the whitespace analyzer.
### Conditional types
`?`/`:` are now tight when minifying, like a JS conditional expression:
| Input | Before | After |
| --- | --- | --- |
| `A extends B ? C : D` | `A extends B ? C : D` | `A extends B?C:D` |
The leading `extends` space is emitted only when the check type ends in an identifier (so `T extends …` keeps it, `{} extends …` doesn't). The space *after* `extends` is kept to avoid merging a following type keyword (`keyof`, etc.).
### Constructor types
No space after `new` before `(`/`<`:
| Input | Before | After |
| --- | --- | --- |
| `new () => Foo` | `new () => Foo` | `new()=>Foo` |
| `abstract new (x: number) => Foo` | `abstract new (x: number) => Foo` | `abstract new(x:number)=>Foo` |
Pretty-print output is unchanged; `ts` minify snapshot updated. Verified round-trip.
This commit is contained in:
3 files changed
+38
-5
No files matched your search
@@ -3331,13 +3331,24 @@ impl Gen for TSConditionalType<'_> {
|
||||
self.check_type.print(p, ctx);
|
||||
},
|
||||
);
|
||||
p.print_str(" extends ");
|
||||
p.print_soft_space();
|
||||
p.print_space_before_identifier();
|
||||
p.print_str("extends ");
|
||||
p.wrap(matches!(self.extends_type, TSType::TSConditionalType(_)), |p| {
|
||||
self.extends_type.print(p, ctx);
|
||||
});
|
||||
p.print_str(" ? ");
|
||||
p.print_soft_space();
|
||||
// Avoid merging into `??` when the extends type ends with `?` (postfix
|
||||
// JSDoc nullable, e.g. `A extends C? ? D : E`).
|
||||
if p.last_byte() == Some(b'?') {
|
||||
p.print_hard_space();
|
||||
}
|
||||
p.print_str("?");
|
||||
p.print_soft_space();
|
||||
self.true_type.print(p, ctx);
|
||||
p.print_str(" : ");
|
||||
p.print_soft_space();
|
||||
p.print_str(":");
|
||||
p.print_soft_space();
|
||||
self.false_type.print(p, ctx);
|
||||
}
|
||||
}
|
||||
@@ -3458,6 +3469,11 @@ impl Gen for JSDocNullableType<'_> {
|
||||
self.type_annotation.print(p, ctx);
|
||||
p.print_ascii_byte(b'?');
|
||||
} else {
|
||||
// Avoid merging into `??` after a preceding `?` (e.g. a conditional type
|
||||
// `A extends B ? ?C : D` minified).
|
||||
if p.last_byte() == Some(b'?') {
|
||||
p.print_hard_space();
|
||||
}
|
||||
p.print_ascii_byte(b'?');
|
||||
self.type_annotation.print(p, ctx);
|
||||
}
|
||||
@@ -4035,7 +4051,8 @@ impl Gen for TSConstructorType<'_> {
|
||||
if self.r#abstract {
|
||||
p.print_str("abstract ");
|
||||
}
|
||||
p.print_str("new ");
|
||||
p.print_str("new");
|
||||
p.print_soft_space();
|
||||
if let Some(type_parameters) = &self.type_parameters {
|
||||
type_parameters.print(p, ctx);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ export{Foo,type Bar}from"foo";
|
||||
########## 15
|
||||
type A<T> = { [K in keyof T as K extends string ? B<K> : K ]: T[K] }
|
||||
----------
|
||||
type A<T>={[K in keyof T as K extends string ? B<K> : K]:T[K]};
|
||||
type A<T>={[K in keyof T as K extends string?B<K>:K]:T[K]};
|
||||
########## 16
|
||||
class A {readonly type = 'frame'}
|
||||
----------
|
||||
|
||||
@@ -207,6 +207,22 @@ fn minify_return_type_colon() {
|
||||
min("function h(this: Foo): void {}", "function h(this:Foo):void{}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minify_ts_type_space() {
|
||||
let min = |src: &str, expected: &str| {
|
||||
test_options_with_source_type(src, expected, SourceType::ts(), CodegenOptions::minify());
|
||||
};
|
||||
// Conditional type: `?`/`:` are tight like a JS conditional expression.
|
||||
min("type T = A extends B ? C : D;", "type T=A extends B?C:D;");
|
||||
min("type T = A extends {} ? B : C;", "type T=A extends {}?B:C;");
|
||||
// Constructor type: no space after `new` before `(`/`<`.
|
||||
min("type N = new () => Foo;", "type N=new()=>Foo;");
|
||||
min("type N = abstract new (x: number) => Foo;", "type N=abstract new(x:number)=>Foo;");
|
||||
// A JSDoc-nullable branch must not merge into `??`.
|
||||
min("type T = A extends B ? ?C : D;", "type T=A extends B? ?C:D;");
|
||||
min("type T = A extends C? ? D : E;", "type T=A extends C? ?D:E;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ts_as_expression_in_binary_expr() {
|
||||
test_idempotency("key in (that as object)");
|
||||
|
||||
Reference in new issue
Block a user