Skip to content

Commit a37138f

Browse files
committed
feat(isolated-declarations): improve the inference template literal (#3797)
1 parent b0d7355 commit a37138f

File tree

7 files changed

+79
-28
lines changed

7 files changed

+79
-28
lines changed

crates/oxc_isolated_declarations/src/declaration.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,12 @@ impl<'a> IsolatedDeclarations<'a> {
7373
if let Some(init_expr) = &decl.init {
7474
// if kind is const and it doesn't need to infer type from expression
7575
if decl.kind.is_const() && !Self::is_need_to_infer_type_from_expression(init_expr) {
76-
init = Some(self.ast.copy(init_expr));
76+
if let Expression::TemplateLiteral(lit) = init_expr {
77+
init =
78+
self.transform_template_to_string(lit).map(Expression::StringLiteral);
79+
} else {
80+
init = Some(self.ast.copy(init_expr));
81+
}
7782
} else {
7883
// otherwise, we need to infer type from expression
7984
binding_type = self.infer_type_from_expression(init_expr);

crates/oxc_isolated_declarations/src/inferrer.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,13 @@ impl<'a> IsolatedDeclarations<'a> {
2121
Expression::NumericLiteral(_) | Expression::BigintLiteral(_) => {
2222
Some(self.ast.ts_number_keyword(SPAN))
2323
}
24-
Expression::StringLiteral(_) | Expression::TemplateLiteral(_) => {
25-
Some(self.ast.ts_string_keyword(SPAN))
24+
Expression::StringLiteral(_) => Some(self.ast.ts_string_keyword(SPAN)),
25+
Expression::TemplateLiteral(lit) => {
26+
if lit.expressions.is_empty() {
27+
Some(self.ast.ts_string_keyword(SPAN))
28+
} else {
29+
None
30+
}
2631
}
2732
Expression::Identifier(ident) => match ident.name.as_str() {
2833
"undefined" => Some(self.ast.ts_undefined_keyword(SPAN)),
@@ -133,12 +138,12 @@ impl<'a> IsolatedDeclarations<'a> {
133138
}
134139

135140
pub fn is_need_to_infer_type_from_expression(expr: &Expression) -> bool {
136-
!matches!(
137-
expr,
141+
match expr {
138142
Expression::NumericLiteral(_)
139-
| Expression::BigintLiteral(_)
140-
| Expression::StringLiteral(_)
141-
| Expression::TemplateLiteral(_)
142-
)
143+
| Expression::BigintLiteral(_)
144+
| Expression::StringLiteral(_) => false,
145+
Expression::TemplateLiteral(lit) => !lit.expressions.is_empty(),
146+
_ => true,
147+
}
143148
}
144149
}

crates/oxc_isolated_declarations/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod diagnostics;
1111
mod r#enum;
1212
mod function;
1313
mod inferrer;
14+
mod literal;
1415
mod module;
1516
mod return_type;
1617
mod scope;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use oxc_allocator::Box;
2+
use oxc_ast::ast::{StringLiteral, TemplateLiteral};
3+
4+
use crate::IsolatedDeclarations;
5+
6+
impl<'a> IsolatedDeclarations<'a> {
7+
pub fn transform_template_to_string(
8+
&self,
9+
lit: &TemplateLiteral<'a>,
10+
) -> Option<Box<'a, StringLiteral<'a>>> {
11+
if lit.expressions.is_empty() {
12+
lit.quasis.first().map(|item| {
13+
self.ast.alloc(self.ast.string_literal(
14+
lit.span,
15+
if let Some(cooked) = &item.value.cooked { cooked } else { &item.value.raw },
16+
))
17+
})
18+
} else {
19+
None
20+
}
21+
}
22+
}

crates/oxc_isolated_declarations/src/types.rs

+3-19
Original file line numberDiff line numberDiff line change
@@ -189,25 +189,9 @@ impl<'a> IsolatedDeclarations<'a> {
189189
"undefined" => Some(self.ast.ts_undefined_keyword(ident.span)),
190190
_ => None,
191191
},
192-
Expression::TemplateLiteral(lit) => {
193-
if lit.expressions.is_empty() {
194-
lit.quasis.first().map(|item| {
195-
self.ast.ts_literal_type(
196-
SPAN,
197-
TSLiteral::StringLiteral(self.ast.alloc(self.ast.string_literal(
198-
lit.span,
199-
if let Some(cooked) = &item.value.cooked {
200-
cooked
201-
} else {
202-
&item.value.raw
203-
},
204-
))),
205-
)
206-
})
207-
} else {
208-
None
209-
}
210-
}
192+
Expression::TemplateLiteral(lit) => self
193+
.transform_template_to_string(lit)
194+
.map(|string| self.ast.ts_literal_type(lit.span, TSLiteral::StringLiteral(string))),
211195
Expression::UnaryExpression(expr) => Some(
212196
self.ast.ts_literal_type(SPAN, TSLiteral::UnaryExpression(self.ast.copy(expr))),
213197
),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const CSS_VARS_HELPER = `useCssVars`
2+
3+
export function g(func = `useCssVar`) : void {}
4+
5+
export const F = {
6+
a: `a`,
7+
b: [`b`]
8+
} as const
9+
10+
export const BAD = `useCssV${v}ars`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
source: crates/oxc_isolated_declarations/tests/mod.rs
3+
input_file: crates/oxc_isolated_declarations/tests/fixtures/infer-template-literal.ts
4+
---
5+
==================== .D.TS ====================
6+
7+
export declare const CSS_VARS_HELPER = 'useCssVars';
8+
export declare function g(func?: string): void;
9+
export declare const F: {
10+
readonly a: 'a';
11+
readonly b: readonly ['b'];
12+
};
13+
export declare const BAD: unknown;
14+
15+
16+
==================== Errors ====================
17+
18+
x TS9010: Variable must have an explicit type annotation with
19+
| --isolatedDeclarations.
20+
,-[10:14]
21+
9 |
22+
10 | export const BAD = `useCssV${v}ars`
23+
: ^^^
24+
`----

0 commit comments

Comments
 (0)