Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions crates/oxc_isolated_declarations/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,11 @@ impl<'a> IsolatedDeclarations<'a> {
type_annotation = property.type_annotation.clone_in(self.ast.allocator);
} else if let Some(expr) = property.value.as_ref() {
let ts_type = if property.readonly {
// `field = 'string'` remain `field = 'string'` instead of `field: 'string'`
if Self::is_need_to_infer_type_from_expression(expr) {
// Keep literal const initializers on readonly class properties to match TS d.ts emit.
if let Some(initializer) = self.get_literal_const_initializer(expr) {
value = Some(initializer);
None
} else if Self::is_need_to_infer_type_from_expression(expr) {
self.transform_expression_to_ts_type(expr)
} else {
if let Expression::TemplateLiteral(lit) = expr {
Expand Down Expand Up @@ -147,6 +150,31 @@ impl<'a> IsolatedDeclarations<'a> {
)
}

fn get_literal_const_initializer(&self, expr: &Expression<'a>) -> Option<Expression<'a>> {
match expr {
Expression::BooleanLiteral(_)
| Expression::NumericLiteral(_)
| Expression::BigIntLiteral(_)
| Expression::StringLiteral(_) => Some(expr.clone_in(self.ast.allocator)),
Expression::TemplateLiteral(lit) if lit.expressions.is_empty() => {
self.transform_template_to_string(lit).map(Expression::StringLiteral)
}
Expression::UnaryExpression(expr) if Self::can_infer_unary_expression(expr) => {
Some(Expression::UnaryExpression(expr.clone_in(self.ast.allocator)))
}
Expression::ParenthesizedExpression(expr) => {
self.get_literal_const_initializer(&expr.expression)
}
Expression::TSAsExpression(expr) if expr.type_annotation.is_const_type_reference() => {
self.get_literal_const_initializer(&expr.expression)
}
Expression::TSTypeAssertion(expr) if expr.type_annotation.is_const_type_reference() => {
self.get_literal_const_initializer(&expr.expression)
}
_ => None,
}
}

fn transform_class_method_definition(
&self,
definition: &MethodDefinition<'a>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export class ReadonlyLiteralInitializers {
readonly directTrue = true;
readonly parenTrue = (true);
readonly constAssertTrue = true as const;
readonly nestedConstAssert = ((true as const));

readonly directString = "x";
readonly parenString = ("x");
readonly templateNoExpr = `x`;
readonly constAssertString = ("x" as const);

readonly unaryNumber = -1;
readonly unaryParenNumber = (-1);
readonly constAssertNumber = (1 as const);

writableTrue = true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export class ReadonlySatisfies {
readonly falseSatisfies = (false satisfies boolean);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
source: crates/oxc_isolated_declarations/tests/mod.rs
input_file: crates/oxc_isolated_declarations/tests/fixtures/readonly-class-property-initializer.ts
---
```
==================== .D.TS ====================

export declare class ReadonlyLiteralInitializers {
readonly directTrue = true;
readonly parenTrue = true;
readonly constAssertTrue = true;
readonly nestedConstAssert = true;
readonly directString = "x";
readonly parenString = "x";
readonly templateNoExpr = "x";
readonly constAssertString = "x";
readonly unaryNumber = -1;
readonly unaryParenNumber = -1;
readonly constAssertNumber = 1;
writableTrue: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
source: crates/oxc_isolated_declarations/tests/mod.rs
input_file: crates/oxc_isolated_declarations/tests/fixtures/readonly-satisfies.ts
---
```
==================== .D.TS ====================

export declare class ReadonlySatisfies {
readonly falseSatisfies;
}


==================== Errors ====================

x TS9012: Property must have an explicit type annotation with
| --isolatedDeclarations.
,-[2:12]
1 | export class ReadonlySatisfies {
2 | readonly falseSatisfies = (false satisfies boolean);
: ^^^^^^^^^^^^^^
3 | }
`----


```
Loading