Skip to content

Commit e05b155

Browse files
committed
feat(linter): add typescript/no-generated-empty-object-type (#26958)
Adds `typescript/no-generated-empty-object-type` as a suspicious type-aware rule, reporting type operations such as `Pick<Data, never>` that resolve to `{}`. Type analysis stays in TSGolint; the rule has no options, fixes, or suggestions. Requires a backend containing oxc-project/tsgolint#1229. The shared type-aware snapshots were validated against a local build of that implementation. This PR leaves the pinned backend package unchanged.
1 parent 88a0096 commit e05b155

13 files changed

Lines changed: 788 additions & 624 deletions

‎apps/oxlint/fixtures/cli/tsgolint/.oxlintrc.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"typescript/no-duplicate-type-constituents": "error",
1515
"typescript/no-floating-promises": "error",
1616
"typescript/no-for-in-array": "error",
17+
"typescript/no-generated-empty-object-type": "error",
1718
"typescript/no-implied-eval": "error",
1819
"typescript/no-meaningless-void-operator": "error",
1920
"typescript/no-misused-spread": "error",
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
type Data = { name: string; value: number };
2+
// These operations resolve to the empty object type.
3+
type EmptyOmit = Omit<Data, "name" | "value">;
4+
type EmptyPick = Pick<Data, never>;
5+
type EmptyNonNullable = NonNullable<unknown>;
6+
type EmptyIntersection = Omit<Data, "name" | "value"> & Omit<Data, "name" | "value">;
7+
// These operations retain properties.
8+
type WithValue = Omit<Data, "name">;
9+
type WithOther = Omit<Data, "name" | "value"> & { other: string };
10+
11+
type Keys<T> = T extends infer U ? keyof U : never;
12+
type Mapped<T extends object> = { [Key in Keys<T>]: Key };
13+
type Referenced<T extends object> = Mapped<T>;
14+
15+
export {};

‎apps/oxlint/src-js/package/config.generated.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,7 @@ export interface DummyRuleMap {
14571457
"typescript/no-extraneous-class"?: RuleNoConfig | [AllowWarnDeny, NoExtraneousClass];
14581458
"typescript/no-floating-promises"?: RuleNoConfig | [AllowWarnDeny, NoFloatingPromisesConfig];
14591459
"typescript/no-for-in-array"?: RuleNoConfig;
1460+
"typescript/no-generated-empty-object-type"?: RuleNoConfig;
14601461
"typescript/no-implied-eval"?: RuleNoConfig;
14611462
"typescript/no-import-type-side-effects"?: RuleNoConfig;
14621463
"typescript/no-inferrable-types"?: RuleNoConfig | [AllowWarnDeny, NoInferrableTypes];

‎apps/oxlint/src/snapshots/fixtures__cli__tsgolint_--type-aware --silent@oxlint.snap‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ arguments: --type-aware --silent
66
working directory: fixtures/cli/tsgolint
77
----------
88

9-
Found 0 warnings and 81 errors.
10-
Finished in <variable>ms on 60 files with 59 rules using 1 threads.
9+
Found 0 warnings and 86 errors.
10+
Finished in <variable>ms on 61 files with 60 rules using 1 threads.
1111
----------
1212
CLI result: LintFoundErrors
1313
----------

‎apps/oxlint/src/snapshots/fixtures__cli__tsgolint_--type-aware -c config-test.json@oxlint.snap‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ working directory: fixtures/cli/tsgolint
4242
help: Remove the debugger statement
4343

4444
Found 2 warnings and 2 errors.
45-
Finished in <variable>ms on 60 files with 2 rules using 1 threads.
45+
Finished in <variable>ms on 61 files with 2 rules using 1 threads.
4646
----------
4747
CLI result: LintFoundErrors
4848
----------

‎apps/oxlint/src/snapshots/fixtures__cli__tsgolint_--type-aware test.svelte@oxlint.snap‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ working directory: fixtures/cli/tsgolint
1616
help: Remove the debugger statement
1717

1818
Found 0 warnings and 1 error.
19-
Finished in <variable>ms on 1 file with 59 rules using 1 threads.
19+
Finished in <variable>ms on 1 file with 60 rules using 1 threads.
2020
----------
2121
CLI result: LintFoundErrors
2222
----------

‎apps/oxlint/src/snapshots/fixtures__cli__tsgolint_--type-aware@oxlint.snap‎

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,47 @@ working directory: fixtures/cli/tsgolint
113113
`----
114114
help: Use a more robust iteration method such as for-of or array.forEach instead.
115115
116+
x typescript(no-generated-empty-object-type): This type resolves to `{}`, the empty object type. This was likely not intentional.
117+
,-[no-generated-empty-object-type.ts:3:18]
118+
2 | // These operations resolve to the empty object type.
119+
3 | type EmptyOmit = Omit<Data, "name" | "value">;
120+
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
121+
4 | type EmptyPick = Pick<Data, never>;
122+
`----
123+
124+
x typescript(no-generated-empty-object-type): This type resolves to `{}`, the empty object type. This was likely not intentional.
125+
,-[no-generated-empty-object-type.ts:4:18]
126+
3 | type EmptyOmit = Omit<Data, "name" | "value">;
127+
4 | type EmptyPick = Pick<Data, never>;
128+
: ^^^^^^^^^^^^^^^^^
129+
5 | type EmptyNonNullable = NonNullable<unknown>;
130+
`----
131+
132+
x typescript(no-generated-empty-object-type): This type resolves to `{}`, the empty object type. This was likely not intentional.
133+
,-[no-generated-empty-object-type.ts:5:25]
134+
4 | type EmptyPick = Pick<Data, never>;
135+
5 | type EmptyNonNullable = NonNullable<unknown>;
136+
: ^^^^^^^^^^^^^^^^^^^^
137+
6 | type EmptyIntersection = Omit<Data, "name" | "value"> & Omit<Data, "name" | "value">;
138+
`----
139+
140+
x typescript(no-duplicate-type-constituents): Intersection type constituent is duplicated with Omit<Data, "name" | "value">.
141+
,-[no-generated-empty-object-type.ts:6:57]
142+
5 | type EmptyNonNullable = NonNullable<unknown>;
143+
6 | type EmptyIntersection = Omit<Data, "name" | "value"> & Omit<Data, "name" | "value">;
144+
: ^^^^^^^^^^^^^^|^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
145+
: `-- Type 'Omit<Data, "name" | "value">' is first declared here.
146+
7 | // These operations retain properties.
147+
`----
148+
149+
x typescript(no-generated-empty-object-type): This type resolves to `{}`, the empty object type. This was likely not intentional.
150+
,-[no-generated-empty-object-type.ts:6:26]
151+
5 | type EmptyNonNullable = NonNullable<unknown>;
152+
6 | type EmptyIntersection = Omit<Data, "name" | "value"> & Omit<Data, "name" | "value">;
153+
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
154+
7 | // These operations retain properties.
155+
`----
156+
116157
x typescript(no-implied-eval): Implied eval.
117158
,-[no-implied-eval.ts:1:12]
118159
1 | setTimeout('alert("Hi!");', 100);
@@ -694,8 +735,8 @@ working directory: fixtures/cli/tsgolint
694735
`----
695736
help: If your function does not access `this`, you can annotate it with `this: void`, or consider using an arrow function instead.
696737
697-
Found 0 warnings and 81 errors.
698-
Finished in <variable>ms on 60 files with 59 rules using 1 threads.
738+
Found 0 warnings and 86 errors.
739+
Finished in <variable>ms on 61 files with 60 rules using 1 threads.
699740
----------
700741
CLI result: LintFoundErrors
701742
----------

‎apps/oxlint/src/snapshots/fixtures__cli__tsgolint_-c config-type-aware.json@oxlint.snap‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ working directory: fixtures/cli/tsgolint
4242
help: Remove the debugger statement
4343

4444
Found 2 warnings and 2 errors.
45-
Finished in <variable>ms on 60 files with 2 rules using 1 threads.
45+
Finished in <variable>ms on 61 files with 2 rules using 1 threads.
4646
----------
4747
CLI result: LintFoundErrors
4848
----------

‎crates/oxc_linter/src/generated/rule_runner_impls.rs‎

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)