fix(isolated-declarations): allow adding undefined to keyof parameter types (#27173)

A defaulted `keyof` parameter followed by a required parameter still reports TS9025, even though tsc 7 accepts it and emits `| undefined`. #27009 handled `readonly` but kept the other type operators on the error path.

The only other operators are `keyof` and `unique`. `keyof X` never includes `undefined`, and `unique symbol` can't appear in a parameter annotation, so every type operator can safely take `| undefined`.

When the rest of the type can't be resolved without a checker, like `(any | undefined) & keyof S`, this now adds a redundant `| undefined` where it used to preserve the annotation. The type is the same. It's the existing behavior for `any` unions, and tsc 7 isn't consistent there either: it widens `any | string` but not `any | keyof {}`.

## Example

```ts
export function keyOf(value: keyof Source = "value", required: string): void {}
```

Before:

```
x TS9025: Declaration emit for this parameter requires implicitly adding
| undefined to it's type. This is not supported with --isolatedDeclarations.
```

After:

```ts
export declare function keyOf(value: keyof Source | undefined, required: string): void;
```

The existing `default-parameter-type-kinds` and `function-parameters` snapshots lose five TS9025 diagnostics. The `keyof` declarations match tsc 7.0.2 output apart from parenthesization.

Follow-up to #27009 (#26944).
This commit is contained in:
Dunqing committed 2026-09-29 06:55:35 +00:00
1 parent 4896287ad8
commit 0c601f4228
3 files changed
+8 -55

No files matched your search

@@ -334,10 +334,8 @@ fn can_add_undefined(ts_type: &TSType<'_>) -> bool {
| TSType::TSTupleType(_)
| TSType::TSTypeLiteral(_)
| TSType::TSTemplateLiteralType(_)
| TSType::TSThisType(_) => true,
TSType::TSTypeOperatorType(operator) => {
operator.operator == TSTypeOperatorOperator::Readonly
}
| TSType::TSThisType(_)
| TSType::TSTypeOperatorType(_) => true,
TSType::TSParenthesizedType(parenthesized) => {
can_add_undefined(&parenthesized.type_annotation)
}
@@ -9,18 +9,18 @@ interface Source {
value: string;
}
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 keyOf(value: keyof Source | undefined, 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;
export declare function operatorIntersection(value: (keyof Source) & string, required: string): void;
export declare function unknownOperatorIntersection(value: unknown & keyof Source, required: string): void;
export declare function operatorIntersection(value: (keyof Source) & string | undefined, required: string): void;
export declare function unknownOperatorIntersection(value: unknown & keyof Source | undefined, required: string): void;
export declare function unresolvedIntersection<T>(value: T & string, required: string): void;
export declare function allUnknownIntersection(value: unknown & unknown | undefined, required: string): void;
export declare function unresolvedUndefinedUnionIntersection<T>(value: (T | undefined) & string, required: string): void;
export declare function unknownUndefinedUnionOperatorIntersection(value: (unknown | undefined) & keyof Source, required: string): void;
export declare function anyUndefinedUnionOperatorIntersection(value: (any | undefined) & keyof Source, required: string): void;
export declare function unknownUndefinedUnionOperatorIntersection(value: (unknown | undefined) & keyof Source | undefined, required: string): void;
export declare function anyUndefinedUnionOperatorIntersection(value: (any | undefined) & keyof Source | undefined, required: string): void;
export declare function unresolvedNeverOperatorIntersection<T>(value: T & never & keyof Source, required: string): void;
export declare function voidUnionUndefinedIntersection(value: (void | string) & undefined, required: string): void;
export {};
@@ -37,42 +37,6 @@ export {};
7 | required: string,
`----
x TS9025: Declaration emit for this parameter requires implicitly adding
| undefined to it's type. This is not supported with --isolatedDeclarations.
,-[11:3]
10 | export function keyOf(
11 | value: keyof Source = "value",
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12 | 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]
25 | export function operatorIntersection(
26 | value: (keyof Source) & string = "value",
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27 | required: string,
`----
x TS9025: Declaration emit for this parameter requires implicitly adding
| undefined to it's type. This is not supported with --isolatedDeclarations.
,-[31:3]
30 | export function unknownOperatorIntersection(
31 | value: unknown & keyof Source = "value",
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32 | required: string,
`----
x TS9025: Declaration emit for this parameter requires implicitly adding
| undefined to it's type. This is not supported with --isolatedDeclarations.
,-[51:3]
50 | export function unknownUndefinedUnionOperatorIntersection(
51 | value: (unknown | undefined) & keyof Source = "value",
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
52 | required: string,
`----
x TS9025: Declaration emit for this parameter requires implicitly adding
| undefined to it's type. This is not supported with --isolatedDeclarations.
,-[61:3]
@@ -22,7 +22,7 @@ export declare function withAnyUndefinedUnion(a: any | undefined, b: string): vo
type Foo = {};
export declare function withAnyTypeReferenceUnion(a: any | Foo, b: string): void;
export declare function withAnyTypeReferenceUndefinedUnion(a: any | Foo | undefined, b: string): void;
export declare function withAnyTypeOperatorUnion(a: any | keyof {}, b: string): void;
export declare function withAnyTypeOperatorUnion(a: any | keyof {} | undefined, b: string): void;
export declare function withAnyIntersectionTypeReferenceUnion(a: any | (Foo & {}), b: string): void;
export declare function withUnknown(a: unknown | undefined, b: string): void;
export declare function withUnknownUnion(a: unknown | string | undefined, b: string): void;
@@ -55,14 +55,5 @@ export {};
27 | return 2;
`----
x TS9025: Declaration emit for this parameter requires implicitly adding
| undefined to it's type. This is not supported with --isolatedDeclarations.
,-[38:42]
37 | export function withAnyTypeReferenceUndefinedUnion(a: any | Foo | undefined = {}, b: string): void { }
38 | export function withAnyTypeOperatorUnion(a: any | keyof {} = 1, b: string): void { }
: ^^^^^^^^^^^^^^^^^^^^^
39 | export function withAnyIntersectionTypeReferenceUnion(a: any | (Foo & {}) = {}, b: string): void { }
`----
```