From ac9638ec0f1ef26a6bbec92cb223f29c49920108 Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Fri, 23 May 2025 11:51:28 +0000 Subject: [PATCH] fix(isolated-declarations): object property key was generated incorrectly (#11231) Just for aligning with `TypeScript`, the object key should be converted to a static property key when possible ```ts const ObjectKeys = { a: 0, ["b"]: 1, [`c`]: 2, [3]: 3, [-3]: 4, [4n]: 5, }; ``` ```ts declare const ObjectKeys: { a: number b: number c: number 3: number [-3]: number }; ``` `BigInt` is invalid as a property key in TypeScript, so `4n` doesn't emit. --- crates/oxc_isolated_declarations/src/class.rs | 4 +-- crates/oxc_isolated_declarations/src/types.rs | 33 ++++++++++++++++--- .../tests/fixtures/object.ts | 9 +++++ .../tests/snapshots/object.snap | 16 +++++++++ tasks/coverage/snapshots/transpile.snap | 6 ++-- 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/crates/oxc_isolated_declarations/src/class.rs b/crates/oxc_isolated_declarations/src/class.rs index 0cad42aaeb3e2..c618a64e5501d 100644 --- a/crates/oxc_isolated_declarations/src/class.rs +++ b/crates/oxc_isolated_declarations/src/class.rs @@ -16,9 +16,7 @@ use crate::{ impl<'a> IsolatedDeclarations<'a> { pub(crate) fn is_literal_key(key: &PropertyKey<'a>) -> bool { match key { - PropertyKey::StringLiteral(_) - | PropertyKey::NumericLiteral(_) - | PropertyKey::BigIntLiteral(_) => true, + PropertyKey::StringLiteral(_) | PropertyKey::NumericLiteral(_) => true, PropertyKey::TemplateLiteral(l) => l.expressions.is_empty(), PropertyKey::UnaryExpression(expr) => { expr.operator.is_arithmetic() diff --git a/crates/oxc_isolated_declarations/src/types.rs b/crates/oxc_isolated_declarations/src/types.rs index 1de5054f99c44..7402629ac34ba 100644 --- a/crates/oxc_isolated_declarations/src/types.rs +++ b/crates/oxc_isolated_declarations/src/types.rs @@ -8,6 +8,7 @@ use oxc_ast::{ }, }; use oxc_span::{ContentEq, GetSpan, SPAN, Span}; +use oxc_syntax::number::ToJsString; use crate::{ IsolatedDeclarations, @@ -65,6 +66,26 @@ impl<'a> IsolatedDeclarations<'a> { }) } + /// Convert a a computed property key to a static property key when possible + fn transform_property_key(&self, key: &PropertyKey<'a>) -> PropertyKey<'a> { + match key { + // [100] -> 100 + PropertyKey::NumericLiteral(literal) => self.ast.property_key_static_identifier( + literal.span, + self.ast.atom(&literal.value.to_js_string()), + ), + // `["string"] -> string` + PropertyKey::StringLiteral(literal) => { + self.ast.property_key_static_identifier(literal.span, literal.value.as_str()) + } + // `[`string`] -> string + PropertyKey::TemplateLiteral(literal) => { + self.ast.property_key_static_identifier(literal.span, literal.quasis[0].value.raw) + } + _ => key.clone_in(self.ast.allocator), + } + } + /// Transform object expression to TypeScript type /// ```ts /// export const obj = { @@ -114,10 +135,13 @@ impl<'a> IsolatedDeclarations<'a> { self.error(method_must_have_explicit_return_type(object.key.span())); } let params = self.transform_formal_parameters(&function.params); + let key = self.transform_property_key(key); + let computed = key.is_expression(); + return Some(self.ast.ts_signature_method_signature( object.span, - key.clone_in(self.ast.allocator), - object.computed, + key, + computed, false, TSMethodSignatureKind::Method, function.type_parameters.clone_in(self.ast.allocator), @@ -187,12 +211,13 @@ impl<'a> IsolatedDeclarations<'a> { } }; + let key = self.transform_property_key(key); let property_signature = self.ast.ts_signature_property_signature( object.span, - false, + key.is_expression(), false, is_const, - key.clone_in(self.ast.allocator), + key, type_annotation, ); Some(property_signature) diff --git a/crates/oxc_isolated_declarations/tests/fixtures/object.ts b/crates/oxc_isolated_declarations/tests/fixtures/object.ts index a9633366e3647..6e13542f4c834 100644 --- a/crates/oxc_isolated_declarations/tests/fixtures/object.ts +++ b/crates/oxc_isolated_declarations/tests/fixtures/object.ts @@ -44,3 +44,12 @@ const ObjectMethods = { b(): number {}, c() {}, }; + +const ObjectKeys = { + a: 0, + ["b"]: 1, + [`c`]: 2, + [3]: 3, + [-3]: 4, + [4n]: 5, +}; diff --git a/crates/oxc_isolated_declarations/tests/snapshots/object.snap b/crates/oxc_isolated_declarations/tests/snapshots/object.snap index e9da5c87cff1b..a6dee2af2c297 100644 --- a/crates/oxc_isolated_declarations/tests/snapshots/object.snap +++ b/crates/oxc_isolated_declarations/tests/snapshots/object.snap @@ -23,6 +23,13 @@ declare const ObjectMethods: { b(): number c() }; +declare const ObjectKeys: { + a: number + b: number + c: number + 3: number + [-3]: number +}; ==================== Errors ==================== @@ -52,5 +59,14 @@ declare const ObjectMethods: { 46 | }; `---- + x TS9038: Computed property names on class or object literals cannot be + | inferred with --isolatedDeclarations. + ,-[54:3] + 53 | [-3]: 4, + 54 | [4n]: 5, + : ^^ + 55 | }; + `---- + ``` diff --git a/tasks/coverage/snapshots/transpile.snap b/tasks/coverage/snapshots/transpile.snap index 5b123d4771125..7670a33a6a576 100644 --- a/tasks/coverage/snapshots/transpile.snap +++ b/tasks/coverage/snapshots/transpile.snap @@ -103,10 +103,10 @@ export declare class C { ["2"]: number; } export declare const D: { - Symbol.iterator: number - globalThis.Symbol.toStringTag: number + [Symbol.iterator]: number + [globalThis.Symbol.toStringTag]: number 1: number - "2": number + 2: number }; export {};