Skip to content

feat(eslint-plugin): [require-types-exports] add rule #10554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
9a0c28a
feat(eslint-plugin): [require-types-exports] add new rule
StyleShit Feb 12, 2024
7778868
wip
StyleShit Feb 12, 2024
12fce5b
wip
StyleShit Feb 12, 2024
d62f86c
lint
StyleShit Feb 13, 2024
0ebebd2
wip
StyleShit Feb 13, 2024
30e9aa9
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Feb 13, 2024
bfee791
spelling...
StyleShit Feb 13, 2024
b309b51
wip
StyleShit Feb 13, 2024
6aa6446
wip
StyleShit Feb 13, 2024
892c368
wip
StyleShit Feb 13, 2024
0e8e58f
tuple generic
StyleShit Feb 13, 2024
f4018a8
wip
StyleShit Feb 13, 2024
89a8344
wip
StyleShit Feb 13, 2024
b2138e3
wip
StyleShit Feb 15, 2024
feedefd
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Feb 15, 2024
1161db0
wip
StyleShit Feb 16, 2024
d9875b3
refactor
StyleShit Feb 16, 2024
6338202
make it shorter & more readable
StyleShit Feb 16, 2024
428b2c1
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Feb 16, 2024
2cb3455
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Apr 24, 2024
1812e37
fix nested types in functions
StyleShit Apr 24, 2024
4bee779
fix docs
StyleShit Apr 24, 2024
26e7be7
add inferred return type test case
StyleShit Apr 24, 2024
e57985a
stupidly check for variable types
StyleShit Apr 24, 2024
cbb784c
support default exported variable
StyleShit Apr 24, 2024
2f2dfa4
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Apr 24, 2024
37a0171
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit May 19, 2024
6fb274a
update docs
StyleShit May 19, 2024
4672fe1
wip
StyleShit May 19, 2024
c79b5cb
wip
StyleShit May 19, 2024
279055a
wip
StyleShit May 19, 2024
7897abf
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit May 28, 2024
7082960
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Jun 2, 2024
2f81933
improve types
StyleShit Jun 2, 2024
0f788d2
improve type reference search
StyleShit Jun 2, 2024
6cec0f5
don't report types from default library
StyleShit Jun 2, 2024
497957a
getTypeName
StyleShit Jun 2, 2024
702d4d0
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Jun 4, 2024
700ff85
move utils out of the closure
StyleShit Jun 4, 2024
9a155b3
support namespaced types
StyleShit Jun 5, 2024
8d0d000
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Jun 5, 2024
b65f9c4
fix namespaced imports
StyleShit Jun 5, 2024
078e24a
WIP
StyleShit Jun 5, 2024
ed23162
wip
StyleShit Jun 5, 2024
ac224eb
fix propertykey tests
StyleShit Jun 5, 2024
417cc91
ReturnType test
StyleShit Jun 5, 2024
62f1466
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Jun 28, 2024
ae1b87c
wip
StyleShit Jun 28, 2024
d227408
collect type references recursively
StyleShit Jun 28, 2024
dca52d0
lib types
StyleShit Jun 28, 2024
ed30856
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Jun 28, 2024
15fc51c
style
StyleShit Jun 28, 2024
59eda58
wip
StyleShit Jun 29, 2024
fc0858a
wip
StyleShit Jun 29, 2024
9d24c64
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Jun 29, 2024
94a98eb
configs
StyleShit Jun 29, 2024
dee0fe4
don't report generic params in call expression
StyleShit Jun 29, 2024
0804b24
improve function types collection
StyleShit Jun 30, 2024
a0a4944
wip
StyleShit Jun 30, 2024
66a0aff
wip
StyleShit Jun 30, 2024
b67e1f9
remove `getVariable`
StyleShit Jun 30, 2024
9891e78
infer return type from return statements
StyleShit Jun 30, 2024
cb90d43
wip
StyleShit Jun 30, 2024
479f593
wip
StyleShit Jun 30, 2024
08f2ce2
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Jun 30, 2024
e86427f
wip
StyleShit Jun 30, 2024
a61d49f
wip
StyleShit Jun 30, 2024
121f475
wip
StyleShit Jun 30, 2024
f3f8518
wip
StyleShit Jun 30, 2024
ab837b4
custom traversal
StyleShit Jul 7, 2024
1641272
some tests
StyleShit Jul 7, 2024
fd56a1c
add missing tests
StyleShit Jul 7, 2024
b0613d5
report default exported call expression
StyleShit Jul 7, 2024
b9f1148
report types used within exported types
StyleShit Jul 7, 2024
0415b60
fix false positives due to ordering
StyleShit Jul 7, 2024
a0c236e
change message
StyleShit Jul 7, 2024
3d5d695
wip
StyleShit Jul 7, 2024
2e76ce6
fix some reports
StyleShit Jul 7, 2024
88713cb
support keyof & typeof
StyleShit Jul 8, 2024
ff2c0a8
simplify tsconfig
StyleShit Jul 8, 2024
2fd30aa
Merge remote-tracking branch 'typescript-eslint/main' into feat/requi…
StyleShit Jul 8, 2024
d977245
Merge branch 'main'
JoshuaKGoldberg Dec 26, 2024
a03713a
Revert unintentional changes
JoshuaKGoldberg Dec 26, 2024
2f44044
Clean up docs
JoshuaKGoldberg Dec 26, 2024
57181fd
Test cleanups
JoshuaKGoldberg Dec 26, 2024
8563e09
Lint and tidy up source a bit
JoshuaKGoldberg Dec 26, 2024
e056cac
Auto updates
JoshuaKGoldberg Dec 26, 2024
196d148
Trim down test empty lines
JoshuaKGoldberg Dec 26, 2024
c42d42f
More exports
JoshuaKGoldberg Dec 26, 2024
e11e05a
More exports
JoshuaKGoldberg Dec 26, 2024
cc90f7d
More exports
JoshuaKGoldberg Dec 26, 2024
5458408
fix: don't report within call expressions
JoshuaKGoldberg Dec 26, 2024
0061e98
Some more cleanups
JoshuaKGoldberg Dec 27, 2024
b629590
Better typeofs and externally declared globals
JoshuaKGoldberg Dec 27, 2024
6de73eb
shared isNodeInside, and more internal progress
JoshuaKGoldberg Dec 27, 2024
4188eb0
Handle already-exported ones, such as namespace children
JoshuaKGoldberg Dec 27, 2024
55cca12
Also check typeof reports for being exported already
JoshuaKGoldberg Dec 27, 2024
fb0c4f3
Merge branch 'main' into require-types-exports-ii-electric-boogaloo
JoshuaKGoldberg Dec 27, 2024
dd7c454
requireTypeQueryExport message
JoshuaKGoldberg Dec 27, 2024
6d04460
requireTypeQueryExport message tweak
JoshuaKGoldberg Dec 27, 2024
e9ada94
Switched report to be on export
JoshuaKGoldberg Dec 27, 2024
e09b7d9
update docs snapshot
JoshuaKGoldberg Dec 27, 2024
8dc9607
Got up to requiring type info...
JoshuaKGoldberg Dec 27, 2024
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
2 changes: 1 addition & 1 deletion packages/ast-spec/src/declaration/ExportAndImportKind.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
type ExportAndImportKind = 'type' | 'value';
export type ExportAndImportKind = 'type' | 'value';

export type ExportKind = ExportAndImportKind;
export type ImportKind = ExportAndImportKind;
4 changes: 2 additions & 2 deletions packages/ast-spec/tests/util/parsers/parser-types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
type SnapshotPathFn = (i: number) => string;
export type SnapshotPathFn = (i: number) => string;

interface SuccessSnapshotPaths {
export interface SuccessSnapshotPaths {
readonly ast: SnapshotPathFn;
readonly tokens: SnapshotPathFn;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@ function escapeTemplateString(code: string): string {
return fixed;
}

type Options = [
export type Options = [
{
// This option exists so that rules like type-annotation-spacing can exist without every test needing a prettier-ignore
formatWithPrettier?: boolean;
},
];

type MessageIds =
export type MessageIds =
| 'invalidFormatting'
| 'invalidFormattingErrorTest'
| 'noUnnecessaryNoFormat'
Expand Down
87 changes: 87 additions & 0 deletions packages/eslint-plugin/docs/rules/require-types-exports.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
description: 'Require exporting types that are used in exported entities.'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

> 🛑 This file is source code, not the primary documentation location! 🛑
>
> See **https://typescript-eslint.io/rules/require-types-exports** for documentation.

When exporting entities from a file, it is often useful to export also all the types that are used in their declarations.
Doing so ensures consumers of the file can directly import and use those types when using those entities.

Otherwise, consumers may have to use utility types like [`Parameters`](https://www.typescriptlang.org/docs/handbook/utility-types.html#parameterstype) or [`ReturnType`](https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype) in order to extract the types from the entities.

## Examples

<Tabs>
<TabItem value="❌ Incorrect">

```ts
interface Fruit {
name: string;
color: string;
}

export const getFruitName = (fruit: Fruit) => fruit.name;
```

```ts
const fruits = {
apple: '🍏',
banana: '🍌',
};

export const getFruit = (key: keyof typeof fruits) => fruits[key];
```

```ts
enum Color {
Red = 'red',
Green = 'green',
Blue = 'blue',
}

export declare function getRandomColor(): Color;
```

</TabItem>
<TabItem value="✅ Correct">

```ts
export interface Fruit {
name: string;
color: string;
}

export const getFruitName = (fruit: Fruit) => fruit.name;
```

```ts
export const fruits = {
apple: '🍏',
banana: '🍌',
};

export const getFruit = (key: keyof typeof fruits) => fruits[key];
```

```ts
export enum Color {
Red = 'red',
Green = 'green',
Blue = 'blue',
}

export declare function getRandomColor(): Color;
```

</TabItem>
</Tabs>

## When Not To Use It

If your files utilize many complex self-referential types that you don't want external consumers to reference, you may want to avoid this rule for those cases.
You might consider using [ESLint disable comments](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments-1) for those specific situations instead of completely disabling this rule.
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/configs/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export = {
'@typescript-eslint/require-array-sort-compare': 'error',
'require-await': 'off',
'@typescript-eslint/require-await': 'error',
'@typescript-eslint/require-types-exports': 'error',
'@typescript-eslint/restrict-plus-operands': 'error',
'@typescript-eslint/restrict-template-expressions': 'error',
'no-return-await': 'off',
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/configs/disable-type-checked.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import type { ClassicConfig } from '@typescript-eslint/utils/ts-eslint';

export = {
parserOptions: { project: false, program: null, projectService: false },
parserOptions: { program: null, project: false, projectService: false },
rules: {
'@typescript-eslint/await-thenable': 'off',
'@typescript-eslint/consistent-return': 'off',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ export = {
{
allowAny: false,
allowBoolean: false,
allowNever: false,
allowNullish: false,
allowNumber: false,
allowRegExp: false,
allowNever: false,
},
],
'no-return-await': 'off',
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/configs/strict-type-checked.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export = {
'@typescript-eslint/related-getter-setter-pairs': 'error',
'require-await': 'off',
'@typescript-eslint/require-await': 'error',
'@typescript-eslint/require-types-exports': 'error',
'@typescript-eslint/restrict-plus-operands': [
'error',
{
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/configs/strict.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export = {
'@typescript-eslint/prefer-as-const': 'error',
'@typescript-eslint/prefer-literal-enum-member': 'error',
'@typescript-eslint/prefer-namespace-keyword': 'error',
'@typescript-eslint/require-types-exports': 'error',
'@typescript-eslint/triple-slash-reference': 'error',
'@typescript-eslint/unified-signatures': 'error',
},
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/rules/array-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ function typeNeedsParentheses(node: TSESTree.Node): boolean {
}

export type OptionString = 'array' | 'array-simple' | 'generic';
type Options = [
export type Options = [
{
default: OptionString;
readonly?: OptionString;
},
];
type MessageIds =
export type MessageIds =
| 'errorStringArray'
| 'errorStringArrayReadonly'
| 'errorStringArraySimple'
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/rules/await-thenable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from '../util';
import { getForStatementHeadLoc } from '../util/getForStatementHeadLoc';

type MessageId =
export type MessageId =
| 'await'
| 'awaitUsingOfNonAsyncDisposable'
| 'convertToOrdinaryFor'
Expand Down
6 changes: 3 additions & 3 deletions packages/eslint-plugin/src/rules/ban-ts-comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { AST_TOKEN_TYPES } from '@typescript-eslint/utils';

import { createRule, getStringLength, nullThrows } from '../util';

type DirectiveConfig =
export type DirectiveConfig =
| boolean
| 'allow-with-description'
| { descriptionFormat: string };

interface Options {
export interface Options {
minimumDescriptionLength?: number;
'ts-check'?: DirectiveConfig;
'ts-expect-error'?: DirectiveConfig;
Expand All @@ -19,7 +19,7 @@ interface Options {

const defaultMinimumDescriptionLength = 3;

type MessageIds =
export type MessageIds =
| 'replaceTsIgnoreWithTsExpectError'
| 'tsDirectiveComment'
| 'tsDirectiveCommentDescriptionNotMatchPattern'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {
nullThrows,
} from '../util';

type Options = ['fields' | 'getters'];
type MessageIds =
export type Options = ['fields' | 'getters'];
export type MessageIds =
| 'preferFieldStyle'
| 'preferFieldStyleSuggestion'
| 'preferGetterStyle'
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/rules/class-methods-use-this.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import {
getStaticMemberAccessValue,
} from '../util';

type Options = [
export type Options = [
{
enforceForClassFields?: boolean;
exceptMethods?: string[];
ignoreClassesThatImplementAnInterface?: boolean | 'public-fields';
ignoreOverrideMethods?: boolean;
},
];
type MessageIds = 'missingThis';
export type MessageIds = 'missingThis';

export default createRule<Options, MessageIds>({
name: 'class-methods-use-this',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils';

import { createRule, nullThrows, NullThrowsReasons } from '../util';

type MessageIds = 'preferConstructor' | 'preferTypeAnnotation';
type Options = ['constructor' | 'type-annotation'];
export type MessageIds = 'preferConstructor' | 'preferTypeAnnotation';
export type Options = ['constructor' | 'type-annotation'];

export default createRule<Options, MessageIds>({
name: 'consistent-generic-constructors',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import {
nullThrows,
} from '../util';

type MessageIds =
export type MessageIds =
| 'preferIndexSignature'
| 'preferIndexSignatureSuggestion'
| 'preferRecord';
type Options = ['index-signature' | 'record'];
export type Options = ['index-signature' | 'record'];

export default createRule<Options, MessageIds>({
name: 'consistent-indexed-object-style',
Expand Down
6 changes: 3 additions & 3 deletions packages/eslint-plugin/src/rules/consistent-return.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import { getESLintCoreRule } from '../util/getESLintCoreRule';

const baseRule = getESLintCoreRule('consistent-return');

type Options = InferOptionsTypeFromRule<typeof baseRule>;
type MessageIds = InferMessageIdsTypeFromRule<typeof baseRule>;
export type Options = InferOptionsTypeFromRule<typeof baseRule>;
export type MessageIds = InferMessageIdsTypeFromRule<typeof baseRule>;

type FunctionNode =
export type FunctionNode =
| TSESTree.ArrowFunctionExpression
| TSESTree.FunctionDeclaration
| TSESTree.FunctionExpression;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type MessageIds =
| 'replaceObjectTypeAssertionWithAnnotation'
| 'replaceObjectTypeAssertionWithSatisfies'
| 'unexpectedObjectTypeAssertion';
type OptUnion =
export type OptUnion =
| {
assertionStyle: 'angle-bracket' | 'as';
objectLiteralTypeAssertions?: 'allow' | 'allow-as-parameter' | 'never';
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/rules/consistent-type-exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
NullThrowsReasons,
} from '../util';

type Options = [
export type Options = [
{
fixMixedExportsWithInlineTypeSpecifier: boolean;
},
Expand All @@ -34,7 +34,7 @@ interface ReportValueExport {
valueSpecifiers: TSESTree.ExportSpecifier[];
}

type MessageIds =
export type MessageIds =
| 'multipleExportsAreTypes'
| 'singleExportIsType'
| 'typeOverValue';
Expand Down
8 changes: 4 additions & 4 deletions packages/eslint-plugin/src/rules/consistent-type-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ import {
NullThrowsReasons,
} from '../util';

type Prefer = 'no-type-imports' | 'type-imports';
type FixStyle = 'inline-type-imports' | 'separate-type-imports';
export type Prefer = 'no-type-imports' | 'type-imports';
export type FixStyle = 'inline-type-imports' | 'separate-type-imports';

type Options = [
export type Options = [
{
disallowTypeAnnotations?: boolean;
fixStyle?: FixStyle;
Expand All @@ -45,7 +45,7 @@ interface ReportValueImport {
valueSpecifiers: TSESTree.ImportClause[];
}

type MessageIds =
export type MessageIds =
| 'avoidImportType'
| 'noImportTypeAnnotations'
| 'someImportsAreOnlyTypes'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
isValidFunctionExpressionReturnType,
} from '../util/explicitReturnTypeUtils';

type Options = [
export type Options = [
{
allowConciseArrowFunctionExpressionsStartingWithVoid?: boolean;
allowDirectConstAssertionInArrowFunctions?: boolean;
Expand All @@ -23,7 +23,7 @@ type Options = [
allowTypedFunctionExpressions?: boolean;
},
];
type MessageIds = 'missingReturnType';
export type MessageIds = 'missingReturnType';

type FunctionNode =
| TSESTree.ArrowFunctionExpression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ import {
} from '../util/getMemberHeadLoc';
import { rangeToLoc } from '../util/rangeToLoc';

type AccessibilityLevel =
export type AccessibilityLevel =
| 'explicit' // require an accessor (including public)
| 'no-public' // don't require public
| 'off'; // don't check

interface Config {
export interface Config {
accessibility?: AccessibilityLevel;
ignoredMethodNames?: string[];
overrides?: {
Expand All @@ -31,9 +31,9 @@ interface Config {
};
}

type Options = [Config];
export type Options = [Config];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note: Next rule has I lined the options and does not have Config as separate type. Maybe for consistency this type could be inlined too, if you are doing another PR just for these export changes :) Or if the separate Config type is preferred, maybe there could be some follow up
task for unifying these.
I don’t feel like this would matter if they would stay as internal types. But after they are exposed to “public”, it would look better if they had unified names. :)


type MessageIds =
export type MessageIds =
| 'addExplicitAccessibility'
| 'missingAccessibility'
| 'unwantedPublicAccessibility';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
isTypedFunctionExpression,
} from '../util/explicitReturnTypeUtils';

type Options = [
export type Options = [
{
allowArgumentsExplicitlyTypedAsAny?: boolean;
allowDirectConstAssertionInArrowFunctions?: boolean;
Expand All @@ -27,7 +27,7 @@ type Options = [
allowTypedFunctionExpressions?: boolean;
},
];
type MessageIds =
export type MessageIds =
| 'anyTypedArg'
| 'anyTypedArgUnnamed'
| 'missingArgType'
Expand Down
Loading
Loading