mirror of
https://github.com/aphrody-labs/oxc.git
synced 2026-10-14 22:29:17 +00:00
fix(isolated-declarations): support readonly parameter types (#27009)
Fixes #26944. Optional parameter properties such as `constructor(readonly value?: readonly string[])` currently produce TS9025 instead of adding `| undefined`. Treat the `readonly` type operator as safe to widen, matching the existing handling of array and tuple types. This also handles readonly defaults followed by required parameters. The change is limited to `readonly`; `keyof`, `unique`, unresolved references, and the existing union-classification policy are unchanged. Unions containing `any` or `unknown` can still emit a redundant `| undefined`; this patch does not attempt full textual parity with TypeScript. Add a diagnostic regression test and declaration snapshots covering arrays, tuples, generic elements, parentheses, unions/intersections, explicit undefined, and optional/default/rest controls. Validation: - The new regression fails with 10 TS9025 diagnostics before the fix and passes after it; all 21 isolated-declarations tests pass. - The 14 declarations in the new fixture match TypeScript 7.0.2 with `exactOptionalPropertyTypes` both enabled and disabled, after normalizing formatting and redundant parentheses. - Strict crate Clippy and formatting checks pass. - The pinned transpiler suite remains at 20/21 on both baseline and patch, with the identical pre-existing `declarationBasicSyntax.ts` mismatch. Run with `--filter ''` to avoid updating the unrelated stale snapshot revision. - Full post-commit `just ready` passes: 4,979 tests passed, 161 ignored, 0 failed; generated files leave the working tree clean. AI assistance: OpenAI Codex was used to investigate, implement, test, and perform a separate automated review of this change. --------- Co-authored-by: Pybsama <294532706+Pybsama@users.noreply.github.com> Co-authored-by: Dunqing <dengqing0821@gmail.com>
This commit is contained in:
4 files changed
+105
-10
No files matched your search
@@ -335,6 +335,9 @@ fn can_add_undefined(ts_type: &TSType<'_>) -> bool {
|
||||
| TSType::TSTypeLiteral(_)
|
||||
| TSType::TSTemplateLiteralType(_)
|
||||
| TSType::TSThisType(_) => true,
|
||||
TSType::TSTypeOperatorType(operator) => {
|
||||
operator.operator == TSTypeOperatorOperator::Readonly
|
||||
}
|
||||
TSType::TSParenthesizedType(parenthesized) => {
|
||||
can_add_undefined(&parenthesized.type_annotation)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
export class ReadonlyArrayProperty {
|
||||
constructor(readonly value?: readonly string[]) {}
|
||||
}
|
||||
|
||||
export class ReadonlyTupleProperty {
|
||||
constructor(public value?: readonly [string, number?]) {}
|
||||
}
|
||||
|
||||
export class GenericReadonlyProperty<T> {
|
||||
constructor(readonly value?: readonly (T | undefined)[]) {}
|
||||
}
|
||||
|
||||
export class ParenthesizedReadonlyProperty {
|
||||
constructor(readonly value?: (readonly string[])) {}
|
||||
}
|
||||
|
||||
export class ReadonlyUnionProperty {
|
||||
constructor(readonly value?: string | readonly string[]) {}
|
||||
}
|
||||
|
||||
export class ReadonlyIntersectionProperty {
|
||||
constructor(readonly value?: (readonly string[]) & { length: number }) {}
|
||||
}
|
||||
|
||||
export class ExplicitUndefinedReadonlyProperty {
|
||||
constructor(readonly value?: readonly string[] | undefined) {}
|
||||
}
|
||||
|
||||
export class DefaultReadonlyProperty {
|
||||
constructor(readonly value: readonly string[] = [], required: string) {}
|
||||
}
|
||||
|
||||
export function defaultReadonlyArray(
|
||||
value: readonly string[] = [],
|
||||
required: string,
|
||||
): void {}
|
||||
|
||||
export function defaultReadonlyTuple(
|
||||
value: readonly [string] = [""],
|
||||
required: string,
|
||||
): void {}
|
||||
|
||||
export function defaultGenericReadonlyArray<T>(
|
||||
value: readonly T[] = [],
|
||||
required: string,
|
||||
): void {}
|
||||
|
||||
export function trailingReadonlyDefault(value: readonly string[] = []): void {}
|
||||
|
||||
export function optionalReadonlyArray(value?: readonly string[]): void {}
|
||||
|
||||
export function readonlyRest(...values: readonly string[]): void {}
|
||||
@@ -10,7 +10,7 @@ interface Source {
|
||||
}
|
||||
export declare function mapped(value: { [K in keyof Source]: Source[K] }, required: string): void;
|
||||
export declare function keyOf(value: keyof Source, required: string): void;
|
||||
export declare function readonlyTuple(value: readonly [string], required: string): void;
|
||||
export declare function readonlyTuple(value: readonly [string] | undefined, required: string): void;
|
||||
export declare function intersection(value: {
|
||||
optional?: string;
|
||||
} & number[] | undefined, required: string): void;
|
||||
@@ -46,15 +46,6 @@ export {};
|
||||
12 | required: string,
|
||||
`----
|
||||
|
||||
x TS9025: Declaration emit for this parameter requires implicitly adding
|
||||
| undefined to it's type. This is not supported with --isolatedDeclarations.
|
||||
,-[16:3]
|
||||
15 | export function readonlyTuple(
|
||||
16 | value: readonly [string] = [""],
|
||||
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
17 | required: string,
|
||||
`----
|
||||
|
||||
x TS9025: Declaration emit for this parameter requires implicitly adding
|
||||
| undefined to it's type. This is not supported with --isolatedDeclarations.
|
||||
,-[26:3]
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
source: crates/oxc_isolated_declarations/tests/mod.rs
|
||||
input_file: crates/oxc_isolated_declarations/tests/fixtures/readonly-parameters.ts
|
||||
---
|
||||
```
|
||||
==================== .D.TS ====================
|
||||
|
||||
export declare class ReadonlyArrayProperty {
|
||||
readonly value?: readonly string[] | undefined;
|
||||
constructor(value?: readonly string[] | undefined);
|
||||
}
|
||||
export declare class ReadonlyTupleProperty {
|
||||
value?: readonly [string, number?] | undefined;
|
||||
constructor(value?: readonly [string, number?] | undefined);
|
||||
}
|
||||
export declare class GenericReadonlyProperty<T> {
|
||||
readonly value?: readonly (T | undefined)[] | undefined;
|
||||
constructor(value?: readonly (T | undefined)[] | undefined);
|
||||
}
|
||||
export declare class ParenthesizedReadonlyProperty {
|
||||
readonly value?: (readonly string[]) | undefined;
|
||||
constructor(value?: (readonly string[]) | undefined);
|
||||
}
|
||||
export declare class ReadonlyUnionProperty {
|
||||
readonly value?: string | readonly string[] | undefined;
|
||||
constructor(value?: string | readonly string[] | undefined);
|
||||
}
|
||||
export declare class ReadonlyIntersectionProperty {
|
||||
readonly value?: (readonly string[]) & {
|
||||
length: number;
|
||||
} | undefined;
|
||||
constructor(value?: (readonly string[]) & {
|
||||
length: number;
|
||||
} | undefined);
|
||||
}
|
||||
export declare class ExplicitUndefinedReadonlyProperty {
|
||||
readonly value?: readonly string[] | undefined;
|
||||
constructor(value?: readonly string[] | undefined);
|
||||
}
|
||||
export declare class DefaultReadonlyProperty {
|
||||
readonly value: readonly string[];
|
||||
constructor(value: readonly string[] | undefined, required: string);
|
||||
}
|
||||
export declare function defaultReadonlyArray(value: readonly string[] | undefined, required: string): void;
|
||||
export declare function defaultReadonlyTuple(value: readonly [string] | undefined, required: string): void;
|
||||
export declare function defaultGenericReadonlyArray<T>(value: readonly T[] | undefined, required: string): void;
|
||||
export declare function trailingReadonlyDefault(value?: readonly string[]): void;
|
||||
export declare function optionalReadonlyArray(value?: readonly string[]): void;
|
||||
export declare function readonlyRest(...values: readonly string[]): void;
|
||||
Reference in new issue
Block a user