fix(isolated_declarations): Infer type of template literal expressions as string (#4068)

In a "non-`const`" context, a template literal string can just be
inferred a `string`. This is consistent with TypeScript's behavior.

Co-authored-by: MichaelMitchell-at <=>
This commit is contained in:
michaelm 2024-07-07 12:41:33 -04:00 committed by GitHub
parent 5472b7c990
commit f8d77e4d7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 42 additions and 20 deletions

View file

@ -77,7 +77,9 @@ impl<'a> IsolatedDeclarations<'a> {
} else {
init = Some(self.ast.copy(init_expr));
}
} else {
} else if !decl.kind.is_const()
|| !matches!(init_expr, Expression::TemplateLiteral(_))
{
// otherwise, we need to infer type from expression
binding_type = self.infer_type_from_expression(init_expr);
}

View file

@ -24,13 +24,8 @@ impl<'a> IsolatedDeclarations<'a> {
Expression::NullLiteral(_) => Some(self.ast.ts_null_keyword(SPAN)),
Expression::NumericLiteral(_) => Some(self.ast.ts_number_keyword(SPAN)),
Expression::BigIntLiteral(_) => Some(self.ast.ts_bigint_keyword(SPAN)),
Expression::StringLiteral(_) => Some(self.ast.ts_string_keyword(SPAN)),
Expression::TemplateLiteral(lit) => {
if lit.expressions.is_empty() {
Some(self.ast.ts_string_keyword(SPAN))
} else {
None
}
Expression::StringLiteral(_) | Expression::TemplateLiteral(_) => {
Some(self.ast.ts_string_keyword(SPAN))
}
Expression::Identifier(ident) => match ident.name.as_str() {
"undefined" => Some(self.ast.ts_undefined_keyword(SPAN)),

View file

@ -6,4 +6,6 @@ function A() {
const B = () => { return B };
const C = function () {}
const C = function () {}
const D = () => `${''}`;

View file

@ -23,5 +23,10 @@ function qux() {
const a = (() => {
return 1;
})();
return `Hello, world!`;
}
return `Hello, world!`;
}
function quux() {
return `${''}`
}
// Inferred type is string

View file

@ -7,4 +7,8 @@ export const F = {
b: [`b`]
} as const
export const BAD = `useCssV${v}ars`
export let GOOD = `useCssV${v}ars`
export const BAD = `useCssV${v}ars`
export let BAD2 = `useCssV${v}ars` as const

View file

@ -7,6 +7,7 @@ input_file: crates/oxc_isolated_declarations/tests/fixtures/arrow-function-retur
declare function A(): unknown;
declare const B: unknown;
declare const C: unknown;
declare const D: () => string;
==================== Errors ====================
@ -31,8 +32,9 @@ declare const C: unknown;
x TS9007: Function must have an explicit return type annotation with
| --isolatedDeclarations.
,-[9:20]
8 |
9 | const C = function () {}
: ^
`----
,-[9:20]
8 |
9 | const C = function () {}
: ^
10 |
`----

View file

@ -8,6 +8,7 @@ declare function foo(): number;
declare function bar(): number | undefined;
declare function baz();
declare function qux(): string;
declare function quux(): string;
==================== Errors ====================

View file

@ -10,15 +10,26 @@ export declare const F: {
readonly a: 'a';
readonly b: readonly ['b'];
};
export declare let GOOD: string;
export declare const BAD: unknown;
export declare let BAD2: unknown;
==================== Errors ====================
x TS9010: Variable must have an explicit type annotation with
| --isolatedDeclarations.
,-[10:14]
9 |
10 | export const BAD = `useCssV${v}ars`
,-[12:14]
11 |
12 | export const BAD = `useCssV${v}ars`
: ^^^
13 |
`----
x TS9010: Variable must have an explicit type annotation with
| --isolatedDeclarations.
,-[14:12]
13 |
14 | export let BAD2 = `useCssV${v}ars` as const
: ^^^^
`----