diff --git a/packages/ast-spec/src/declaration/ExportAndImportKind.ts b/packages/ast-spec/src/declaration/ExportAndImportKind.ts
index e8d90b767981..fe25bf739124 100644
--- a/packages/ast-spec/src/declaration/ExportAndImportKind.ts
+++ b/packages/ast-spec/src/declaration/ExportAndImportKind.ts
@@ -1,4 +1,4 @@
-type ExportAndImportKind = 'type' | 'value';
+export type ExportAndImportKind = 'type' | 'value';
export type ExportKind = ExportAndImportKind;
export type ImportKind = ExportAndImportKind;
diff --git a/packages/ast-spec/tests/util/parsers/parser-types.ts b/packages/ast-spec/tests/util/parsers/parser-types.ts
index 6c96e3d893f6..add78f34e5c4 100644
--- a/packages/ast-spec/tests/util/parsers/parser-types.ts
+++ b/packages/ast-spec/tests/util/parsers/parser-types.ts
@@ -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;
}
diff --git a/packages/eslint-plugin-internal/src/rules/plugin-test-formatting.ts b/packages/eslint-plugin-internal/src/rules/plugin-test-formatting.ts
index 26fcc60d8d2b..1b632fdd0972 100644
--- a/packages/eslint-plugin-internal/src/rules/plugin-test-formatting.ts
+++ b/packages/eslint-plugin-internal/src/rules/plugin-test-formatting.ts
@@ -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'
diff --git a/packages/eslint-plugin/docs/rules/require-types-exports.mdx b/packages/eslint-plugin/docs/rules/require-types-exports.mdx
new file mode 100644
index 000000000000..a96076bf4ca8
--- /dev/null
+++ b/packages/eslint-plugin/docs/rules/require-types-exports.mdx
@@ -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
+
+
+
+
+```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;
+```
+
+
+
+
+```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;
+```
+
+
+
+
+## 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.
diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts
index cd77c7dc2835..1026da596f9f 100644
--- a/packages/eslint-plugin/src/configs/all.ts
+++ b/packages/eslint-plugin/src/configs/all.ts
@@ -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',
diff --git a/packages/eslint-plugin/src/configs/disable-type-checked.ts b/packages/eslint-plugin/src/configs/disable-type-checked.ts
index 061df20cdd65..95efeca0cd5b 100644
--- a/packages/eslint-plugin/src/configs/disable-type-checked.ts
+++ b/packages/eslint-plugin/src/configs/disable-type-checked.ts
@@ -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',
diff --git a/packages/eslint-plugin/src/configs/strict-type-checked-only.ts b/packages/eslint-plugin/src/configs/strict-type-checked-only.ts
index c235c02e7b81..e5be4357f195 100644
--- a/packages/eslint-plugin/src/configs/strict-type-checked-only.ts
+++ b/packages/eslint-plugin/src/configs/strict-type-checked-only.ts
@@ -61,10 +61,10 @@ export = {
{
allowAny: false,
allowBoolean: false,
+ allowNever: false,
allowNullish: false,
allowNumber: false,
allowRegExp: false,
- allowNever: false,
},
],
'no-return-await': 'off',
diff --git a/packages/eslint-plugin/src/configs/strict-type-checked.ts b/packages/eslint-plugin/src/configs/strict-type-checked.ts
index b00f5eb0fc14..4090df8ffe99 100644
--- a/packages/eslint-plugin/src/configs/strict-type-checked.ts
+++ b/packages/eslint-plugin/src/configs/strict-type-checked.ts
@@ -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',
{
diff --git a/packages/eslint-plugin/src/configs/strict.ts b/packages/eslint-plugin/src/configs/strict.ts
index 0e655d1464ca..318ae49b83e5 100644
--- a/packages/eslint-plugin/src/configs/strict.ts
+++ b/packages/eslint-plugin/src/configs/strict.ts
@@ -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',
},
diff --git a/packages/eslint-plugin/src/rules/array-type.ts b/packages/eslint-plugin/src/rules/array-type.ts
index 08330497cb82..5b6badddfc3d 100644
--- a/packages/eslint-plugin/src/rules/array-type.ts
+++ b/packages/eslint-plugin/src/rules/array-type.ts
@@ -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'
diff --git a/packages/eslint-plugin/src/rules/await-thenable.ts b/packages/eslint-plugin/src/rules/await-thenable.ts
index 6fb49227470a..06550d6d49ab 100644
--- a/packages/eslint-plugin/src/rules/await-thenable.ts
+++ b/packages/eslint-plugin/src/rules/await-thenable.ts
@@ -15,7 +15,7 @@ import {
} from '../util';
import { getForStatementHeadLoc } from '../util/getForStatementHeadLoc';
-type MessageId =
+export type MessageId =
| 'await'
| 'awaitUsingOfNonAsyncDisposable'
| 'convertToOrdinaryFor'
diff --git a/packages/eslint-plugin/src/rules/ban-ts-comment.ts b/packages/eslint-plugin/src/rules/ban-ts-comment.ts
index 61ded7aabf4b..ffa347713ad3 100644
--- a/packages/eslint-plugin/src/rules/ban-ts-comment.ts
+++ b/packages/eslint-plugin/src/rules/ban-ts-comment.ts
@@ -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;
@@ -19,7 +19,7 @@ interface Options {
const defaultMinimumDescriptionLength = 3;
-type MessageIds =
+export type MessageIds =
| 'replaceTsIgnoreWithTsExpectError'
| 'tsDirectiveComment'
| 'tsDirectiveCommentDescriptionNotMatchPattern'
diff --git a/packages/eslint-plugin/src/rules/class-literal-property-style.ts b/packages/eslint-plugin/src/rules/class-literal-property-style.ts
index 1819abab966b..2e5cbfb5293f 100644
--- a/packages/eslint-plugin/src/rules/class-literal-property-style.ts
+++ b/packages/eslint-plugin/src/rules/class-literal-property-style.ts
@@ -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'
diff --git a/packages/eslint-plugin/src/rules/class-methods-use-this.ts b/packages/eslint-plugin/src/rules/class-methods-use-this.ts
index 9283de326301..e616ff577ca9 100644
--- a/packages/eslint-plugin/src/rules/class-methods-use-this.ts
+++ b/packages/eslint-plugin/src/rules/class-methods-use-this.ts
@@ -9,7 +9,7 @@ import {
getStaticMemberAccessValue,
} from '../util';
-type Options = [
+export type Options = [
{
enforceForClassFields?: boolean;
exceptMethods?: string[];
@@ -17,7 +17,7 @@ type Options = [
ignoreOverrideMethods?: boolean;
},
];
-type MessageIds = 'missingThis';
+export type MessageIds = 'missingThis';
export default createRule({
name: 'class-methods-use-this',
diff --git a/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts b/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts
index 9c92cd98188c..3fb841c122df 100644
--- a/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts
+++ b/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts
@@ -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({
name: 'consistent-generic-constructors',
diff --git a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts
index 15ab691b38dd..cc9c82a11187 100644
--- a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts
+++ b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts
@@ -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({
name: 'consistent-indexed-object-style',
diff --git a/packages/eslint-plugin/src/rules/consistent-return.ts b/packages/eslint-plugin/src/rules/consistent-return.ts
index 2c18a3cb979f..427ede7fe6f7 100644
--- a/packages/eslint-plugin/src/rules/consistent-return.ts
+++ b/packages/eslint-plugin/src/rules/consistent-return.ts
@@ -13,10 +13,10 @@ import { getESLintCoreRule } from '../util/getESLintCoreRule';
const baseRule = getESLintCoreRule('consistent-return');
-type Options = InferOptionsTypeFromRule;
-type MessageIds = InferMessageIdsTypeFromRule;
+export type Options = InferOptionsTypeFromRule;
+export type MessageIds = InferMessageIdsTypeFromRule;
-type FunctionNode =
+export type FunctionNode =
| TSESTree.ArrowFunctionExpression
| TSESTree.FunctionDeclaration
| TSESTree.FunctionExpression;
diff --git a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts
index 8713405115d9..cd7d514e0f0c 100644
--- a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts
+++ b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts
@@ -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';
diff --git a/packages/eslint-plugin/src/rules/consistent-type-exports.ts b/packages/eslint-plugin/src/rules/consistent-type-exports.ts
index eb610ae84105..214d4402ced4 100644
--- a/packages/eslint-plugin/src/rules/consistent-type-exports.ts
+++ b/packages/eslint-plugin/src/rules/consistent-type-exports.ts
@@ -14,7 +14,7 @@ import {
NullThrowsReasons,
} from '../util';
-type Options = [
+export type Options = [
{
fixMixedExportsWithInlineTypeSpecifier: boolean;
},
@@ -34,7 +34,7 @@ interface ReportValueExport {
valueSpecifiers: TSESTree.ExportSpecifier[];
}
-type MessageIds =
+export type MessageIds =
| 'multipleExportsAreTypes'
| 'singleExportIsType'
| 'typeOverValue';
diff --git a/packages/eslint-plugin/src/rules/consistent-type-imports.ts b/packages/eslint-plugin/src/rules/consistent-type-imports.ts
index 40b088d29245..6910005c47d7 100644
--- a/packages/eslint-plugin/src/rules/consistent-type-imports.ts
+++ b/packages/eslint-plugin/src/rules/consistent-type-imports.ts
@@ -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;
@@ -45,7 +45,7 @@ interface ReportValueImport {
valueSpecifiers: TSESTree.ImportClause[];
}
-type MessageIds =
+export type MessageIds =
| 'avoidImportType'
| 'noImportTypeAnnotations'
| 'someImportsAreOnlyTypes'
diff --git a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts
index 186241cb72a2..a8ee4aa3766b 100644
--- a/packages/eslint-plugin/src/rules/explicit-function-return-type.ts
+++ b/packages/eslint-plugin/src/rules/explicit-function-return-type.ts
@@ -11,7 +11,7 @@ import {
isValidFunctionExpressionReturnType,
} from '../util/explicitReturnTypeUtils';
-type Options = [
+export type Options = [
{
allowConciseArrowFunctionExpressionsStartingWithVoid?: boolean;
allowDirectConstAssertionInArrowFunctions?: boolean;
@@ -23,7 +23,7 @@ type Options = [
allowTypedFunctionExpressions?: boolean;
},
];
-type MessageIds = 'missingReturnType';
+export type MessageIds = 'missingReturnType';
type FunctionNode =
| TSESTree.ArrowFunctionExpression
diff --git a/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts b/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts
index 7dff44c330f9..07b871077fdf 100644
--- a/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts
+++ b/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts
@@ -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?: {
@@ -31,9 +31,9 @@ interface Config {
};
}
-type Options = [Config];
+export type Options = [Config];
-type MessageIds =
+export type MessageIds =
| 'addExplicitAccessibility'
| 'missingAccessibility'
| 'unwantedPublicAccessibility';
diff --git a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts
index 496719db3f37..eaa7b8baf0b4 100644
--- a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts
+++ b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts
@@ -18,7 +18,7 @@ import {
isTypedFunctionExpression,
} from '../util/explicitReturnTypeUtils';
-type Options = [
+export type Options = [
{
allowArgumentsExplicitlyTypedAsAny?: boolean;
allowDirectConstAssertionInArrowFunctions?: boolean;
@@ -27,7 +27,7 @@ type Options = [
allowTypedFunctionExpressions?: boolean;
},
];
-type MessageIds =
+export type MessageIds =
| 'anyTypedArg'
| 'anyTypedArgUnnamed'
| 'missingArgType'
diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts
index de51a8bea55d..548710ee0dfe 100644
--- a/packages/eslint-plugin/src/rules/index.ts
+++ b/packages/eslint-plugin/src/rules/index.ts
@@ -118,6 +118,7 @@ import promiseFunctionAsync from './promise-function-async';
import relatedGetterSetterPairs from './related-getter-setter-pairs';
import requireArraySortCompare from './require-array-sort-compare';
import requireAwait from './require-await';
+import requireTypesExports from './require-types-exports';
import restrictPlusOperands from './restrict-plus-operands';
import restrictTemplateExpressions from './restrict-template-expressions';
import returnAwait from './return-await';
@@ -250,6 +251,7 @@ const rules = {
'related-getter-setter-pairs': relatedGetterSetterPairs,
'require-array-sort-compare': requireArraySortCompare,
'require-await': requireAwait,
+ 'require-types-exports': requireTypesExports,
'restrict-plus-operands': restrictPlusOperands,
'restrict-template-expressions': restrictTemplateExpressions,
'return-await': returnAwait,
diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts
index 83b297152267..dfffdb16d1dc 100644
--- a/packages/eslint-plugin/src/rules/member-ordering.ts
+++ b/packages/eslint-plugin/src/rules/member-ordering.ts
@@ -18,9 +18,9 @@ export type MessageIds =
| 'incorrectOrder'
| 'incorrectRequiredMembersOrder';
-type ReadonlyType = 'readonly-field' | 'readonly-signature';
+export type ReadonlyType = 'readonly-field' | 'readonly-signature';
-type MemberKind =
+export type MemberKind =
| 'accessor'
| 'call-signature'
| 'constructor'
@@ -32,7 +32,7 @@ type MemberKind =
| 'static-initialization'
| ReadonlyType;
-type DecoratedMemberKind =
+export type DecoratedMemberKind =
| 'accessor'
| 'field'
| 'get'
@@ -40,16 +40,16 @@ type DecoratedMemberKind =
| 'set'
| Exclude;
-type NonCallableMemberKind = Exclude<
+export type NonCallableMemberKind = Exclude<
MemberKind,
'constructor' | 'readonly-signature' | 'signature'
>;
-type MemberScope = 'abstract' | 'instance' | 'static';
+export type MemberScope = 'abstract' | 'instance' | 'static';
-type Accessibility = '#private' | TSESTree.Accessibility;
+export type Accessibility = '#private' | TSESTree.Accessibility;
-type BaseMemberType =
+export type BaseMemberType =
| `${Accessibility}-${Exclude<
MemberKind,
'readonly-signature' | 'signature' | 'static-initialization'
@@ -60,26 +60,26 @@ type BaseMemberType =
| `decorated-${DecoratedMemberKind}`
| MemberKind;
-type MemberType = BaseMemberType | BaseMemberType[];
+export type MemberType = BaseMemberType | BaseMemberType[];
-type AlphabeticalOrder =
+export type AlphabeticalOrder =
| 'alphabetically'
| 'alphabetically-case-insensitive'
| 'natural'
| 'natural-case-insensitive';
-type Order = 'as-written' | AlphabeticalOrder;
+export type Order = 'as-written' | AlphabeticalOrder;
-interface SortedOrderConfig {
+export interface SortedOrderConfig {
memberTypes?: 'never' | MemberType[];
optionalityOrder?: OptionalityOrder;
order?: Order;
}
-type OrderConfig = 'never' | MemberType[] | SortedOrderConfig;
+export type OrderConfig = 'never' | MemberType[] | SortedOrderConfig;
type Member = TSESTree.ClassElement | TSESTree.TypeElement;
-type OptionalityOrder = 'optional-first' | 'required-first';
+export type OptionalityOrder = 'optional-first' | 'required-first';
export type Options = [
{
diff --git a/packages/eslint-plugin/src/rules/naming-convention.ts b/packages/eslint-plugin/src/rules/naming-convention.ts
index 736bfdadc407..03500d825163 100644
--- a/packages/eslint-plugin/src/rules/naming-convention.ts
+++ b/packages/eslint-plugin/src/rules/naming-convention.ts
@@ -21,7 +21,7 @@ import {
} from '../util';
import { Modifiers, parseOptions, SCHEMA } from './naming-convention-utils';
-type MessageIds =
+export type MessageIds =
| 'doesNotMatchFormat'
| 'doesNotMatchFormatTrimmed'
| 'missingAffix'
@@ -32,7 +32,7 @@ type MessageIds =
// Note that this intentionally does not strictly type the modifiers/types properties.
// This is because doing so creates a huge headache, as the rule's code doesn't need to care.
// The JSON Schema strictly types these properties, so we know the user won't input invalid config.
-type Options = Selector[];
+export type Options = Selector[];
// This essentially mirrors ESLint's `camelcase` rule
// note that that rule ignores leading and trailing underscores and only checks those in the middle of a variable name
@@ -789,5 +789,3 @@ function requiresQuoting(
: `${node.value}`;
return _requiresQuoting(name, target);
}
-
-export type { MessageIds, Options };
diff --git a/packages/eslint-plugin/src/rules/no-array-delete.ts b/packages/eslint-plugin/src/rules/no-array-delete.ts
index a179418a7b01..900ac576db08 100644
--- a/packages/eslint-plugin/src/rules/no-array-delete.ts
+++ b/packages/eslint-plugin/src/rules/no-array-delete.ts
@@ -9,7 +9,7 @@ import {
getParserServices,
} from '../util';
-type MessageId = 'noArrayDelete' | 'useSplice';
+export type MessageId = 'noArrayDelete' | 'useSplice';
export default createRule<[], MessageId>({
name: 'no-array-delete',
diff --git a/packages/eslint-plugin/src/rules/no-base-to-string.ts b/packages/eslint-plugin/src/rules/no-base-to-string.ts
index b681f820a3b0..e56a312b0fba 100644
--- a/packages/eslint-plugin/src/rules/no-base-to-string.ts
+++ b/packages/eslint-plugin/src/rules/no-base-to-string.ts
@@ -18,12 +18,12 @@ enum Usefulness {
Sometimes = 'may',
}
-type Options = [
+export type Options = [
{
ignoredTypeNames?: string[];
},
];
-type MessageIds = 'baseArrayJoin' | 'baseToString';
+export type MessageIds = 'baseArrayJoin' | 'baseToString';
export default createRule({
name: 'no-base-to-string',
diff --git a/packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts b/packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts
index 101f3514835b..d6ab0531ad80 100644
--- a/packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts
+++ b/packages/eslint-plugin/src/rules/no-confusing-non-null-assertion.ts
@@ -8,7 +8,7 @@ import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils';
import { createRule } from '../util';
-type MessageId =
+export type MessageId =
| 'confusingAssign'
| 'confusingEqual'
| 'confusingOperator'
diff --git a/packages/eslint-plugin/src/rules/no-dupe-class-members.ts b/packages/eslint-plugin/src/rules/no-dupe-class-members.ts
index fe4a50c861d6..4bdfd016eb3c 100644
--- a/packages/eslint-plugin/src/rules/no-dupe-class-members.ts
+++ b/packages/eslint-plugin/src/rules/no-dupe-class-members.ts
@@ -12,8 +12,8 @@ import { getESLintCoreRule } from '../util/getESLintCoreRule';
const baseRule = getESLintCoreRule('no-dupe-class-members');
-type Options = InferOptionsTypeFromRule;
-type MessageIds = InferMessageIdsTypeFromRule;
+export type Options = InferOptionsTypeFromRule;
+export type MessageIds = InferMessageIdsTypeFromRule;
export default createRule({
name: 'no-dupe-class-members',
diff --git a/packages/eslint-plugin/src/rules/no-empty-function.ts b/packages/eslint-plugin/src/rules/no-empty-function.ts
index ac51f32692a2..f805ca0e44d3 100644
--- a/packages/eslint-plugin/src/rules/no-empty-function.ts
+++ b/packages/eslint-plugin/src/rules/no-empty-function.ts
@@ -13,8 +13,8 @@ import { getESLintCoreRule } from '../util/getESLintCoreRule';
const baseRule = getESLintCoreRule('no-empty-function');
-type Options = InferOptionsTypeFromRule;
-type MessageIds = InferMessageIdsTypeFromRule;
+export type Options = InferOptionsTypeFromRule;
+export type MessageIds = InferMessageIdsTypeFromRule;
const defaultOptions: Options = [
{
diff --git a/packages/eslint-plugin/src/rules/no-empty-interface.ts b/packages/eslint-plugin/src/rules/no-empty-interface.ts
index 855d228dbd34..1a2948bc7fb3 100644
--- a/packages/eslint-plugin/src/rules/no-empty-interface.ts
+++ b/packages/eslint-plugin/src/rules/no-empty-interface.ts
@@ -5,12 +5,12 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { createRule, isDefinitionFile } from '../util';
-type Options = [
+export type Options = [
{
allowSingleExtends?: boolean;
},
];
-type MessageIds = 'noEmpty' | 'noEmptyWithSuper';
+export type MessageIds = 'noEmpty' | 'noEmptyWithSuper';
export default createRule({
name: 'no-empty-interface',
diff --git a/packages/eslint-plugin/src/rules/no-extraneous-class.ts b/packages/eslint-plugin/src/rules/no-extraneous-class.ts
index 6a80ba9b876d..b5a4a19a1cb1 100644
--- a/packages/eslint-plugin/src/rules/no-extraneous-class.ts
+++ b/packages/eslint-plugin/src/rules/no-extraneous-class.ts
@@ -4,7 +4,7 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { createRule } from '../util';
-type Options = [
+export type Options = [
{
allowConstructorOnly?: boolean;
allowEmpty?: boolean;
@@ -12,7 +12,7 @@ type Options = [
allowWithDecorator?: boolean;
},
];
-type MessageIds = 'empty' | 'onlyConstructor' | 'onlyStatic';
+export type MessageIds = 'empty' | 'onlyConstructor' | 'onlyStatic';
export default createRule({
name: 'no-extraneous-class',
diff --git a/packages/eslint-plugin/src/rules/no-floating-promises.ts b/packages/eslint-plugin/src/rules/no-floating-promises.ts
index dbbad264d7a0..880ae86cb838 100644
--- a/packages/eslint-plugin/src/rules/no-floating-promises.ts
+++ b/packages/eslint-plugin/src/rules/no-floating-promises.ts
@@ -18,7 +18,7 @@ import {
typeMatchesSomeSpecifier,
} from '../util';
-type Options = [
+export type Options = [
{
allowForKnownSafeCalls?: TypeOrValueSpecifier[];
allowForKnownSafePromises?: TypeOrValueSpecifier[];
@@ -28,7 +28,7 @@ type Options = [
},
];
-type MessageId =
+export type MessageId =
| 'floating'
| 'floatingFixAwait'
| 'floatingFixVoid'
diff --git a/packages/eslint-plugin/src/rules/no-import-type-side-effects.ts b/packages/eslint-plugin/src/rules/no-import-type-side-effects.ts
index 12887dd2331e..a63fe2c85a16 100644
--- a/packages/eslint-plugin/src/rules/no-import-type-side-effects.ts
+++ b/packages/eslint-plugin/src/rules/no-import-type-side-effects.ts
@@ -10,8 +10,8 @@ import {
NullThrowsReasons,
} from '../util';
-type Options = [];
-type MessageIds = 'useTopLevelQualifier';
+export type Options = [];
+export type MessageIds = 'useTopLevelQualifier';
export default createRule({
name: 'no-import-type-side-effects',
diff --git a/packages/eslint-plugin/src/rules/no-inferrable-types.ts b/packages/eslint-plugin/src/rules/no-inferrable-types.ts
index 8c8c7c5b1dee..8c18f786e143 100644
--- a/packages/eslint-plugin/src/rules/no-inferrable-types.ts
+++ b/packages/eslint-plugin/src/rules/no-inferrable-types.ts
@@ -5,13 +5,13 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { createRule, nullThrows, NullThrowsReasons } from '../util';
-type Options = [
+export type Options = [
{
ignoreParameters?: boolean;
ignoreProperties?: boolean;
},
];
-type MessageIds = 'noInferrableType';
+export type MessageIds = 'noInferrableType';
export default createRule({
name: 'no-inferrable-types',
diff --git a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts
index ce41636f9ff3..ea2981794d06 100644
--- a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts
+++ b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts
@@ -4,12 +4,12 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { createRule } from '../util';
-interface Options {
+export interface Options {
allowAsThisParameter?: boolean;
allowInGenericTypeArguments?: boolean | [string, ...string[]];
}
-type MessageIds =
+export type MessageIds =
| 'invalidVoidForGeneric'
| 'invalidVoidNotReturn'
| 'invalidVoidNotReturnOrGeneric'
diff --git a/packages/eslint-plugin/src/rules/no-loop-func.ts b/packages/eslint-plugin/src/rules/no-loop-func.ts
index 0a5fde3dc173..7446d767a6d8 100644
--- a/packages/eslint-plugin/src/rules/no-loop-func.ts
+++ b/packages/eslint-plugin/src/rules/no-loop-func.ts
@@ -7,13 +7,13 @@ import type {
InferOptionsTypeFromRule,
} from '../util';
-import { createRule } from '../util';
+import { createRule, isNodeInside } from '../util';
import { getESLintCoreRule } from '../util/getESLintCoreRule';
const baseRule = getESLintCoreRule('no-loop-func');
-type Options = InferOptionsTypeFromRule;
-type MessageIds = InferMessageIdsTypeFromRule;
+export type Options = InferOptionsTypeFromRule;
+export type MessageIds = InferMessageIdsTypeFromRule;
export default createRule({
name: 'no-loop-func',
@@ -153,8 +153,7 @@ export default createRule({
if (
kind === 'let' &&
declaration &&
- declaration.range[0] > loopNode.range[0] &&
- declaration.range[1] < loopNode.range[1]
+ isNodeInside(declaration, loopNode)
) {
return true;
}
diff --git a/packages/eslint-plugin/src/rules/no-loss-of-precision.ts b/packages/eslint-plugin/src/rules/no-loss-of-precision.ts
index 1fad4ba75799..9c3374280d96 100644
--- a/packages/eslint-plugin/src/rules/no-loss-of-precision.ts
+++ b/packages/eslint-plugin/src/rules/no-loss-of-precision.ts
@@ -8,8 +8,10 @@ import { getESLintCoreRule } from '../util/getESLintCoreRule';
const baseRule = getESLintCoreRule('no-loss-of-precision');
-type Options = InferOptionsTypeFromRule>;
-type MessageIds = InferMessageIdsTypeFromRule>;
+export type Options = InferOptionsTypeFromRule>;
+export type MessageIds = InferMessageIdsTypeFromRule<
+ NonNullable
+>;
export default createRule({
name: 'no-loss-of-precision',
diff --git a/packages/eslint-plugin/src/rules/no-magic-numbers.ts b/packages/eslint-plugin/src/rules/no-magic-numbers.ts
index 9bfbab7a7b48..6ecddefd0645 100644
--- a/packages/eslint-plugin/src/rules/no-magic-numbers.ts
+++ b/packages/eslint-plugin/src/rules/no-magic-numbers.ts
@@ -13,8 +13,8 @@ import { getESLintCoreRule } from '../util/getESLintCoreRule';
const baseRule = getESLintCoreRule('no-magic-numbers');
-type Options = InferOptionsTypeFromRule;
-type MessageIds = InferMessageIdsTypeFromRule;
+export type Options = InferOptionsTypeFromRule;
+export type MessageIds = InferMessageIdsTypeFromRule;
// Extend base schema with additional property to ignore TS numeric literal types
const schema = deepMerge(
diff --git a/packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts b/packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts
index 3529b02998de..9419bde84ed0 100644
--- a/packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts
+++ b/packages/eslint-plugin/src/rules/no-meaningless-void-operator.ts
@@ -6,7 +6,7 @@ import * as ts from 'typescript';
import { createRule } from '../util';
-type Options = [
+export type Options = [
{
checkNever: boolean;
},
diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts
index d806f4c59bfa..82b7c3d0ce30 100644
--- a/packages/eslint-plugin/src/rules/no-misused-promises.ts
+++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts
@@ -15,7 +15,7 @@ import {
NullThrowsReasons,
} from '../util';
-type Options = [
+export type Options = [
{
checksConditionals?: boolean;
checksSpreads?: boolean;
@@ -23,7 +23,7 @@ type Options = [
},
];
-interface ChecksVoidReturnOptions {
+export interface ChecksVoidReturnOptions {
arguments?: boolean;
attributes?: boolean;
inheritedMethods?: boolean;
@@ -32,7 +32,7 @@ interface ChecksVoidReturnOptions {
variables?: boolean;
}
-type MessageId =
+export type MessageId =
| 'conditional'
| 'predicate'
| 'spread'
diff --git a/packages/eslint-plugin/src/rules/no-namespace.ts b/packages/eslint-plugin/src/rules/no-namespace.ts
index 38567e5c90d1..02421a25dea9 100644
--- a/packages/eslint-plugin/src/rules/no-namespace.ts
+++ b/packages/eslint-plugin/src/rules/no-namespace.ts
@@ -4,13 +4,13 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { createRule, isDefinitionFile } from '../util';
-type Options = [
+export type Options = [
{
allowDeclarations?: boolean;
allowDefinitionFiles?: boolean;
},
];
-type MessageIds = 'moduleSyntaxIsPreferred';
+export type MessageIds = 'moduleSyntaxIsPreferred';
export default createRule({
name: 'no-namespace',
diff --git a/packages/eslint-plugin/src/rules/no-non-null-assertion.ts b/packages/eslint-plugin/src/rules/no-non-null-assertion.ts
index d31e9a03da63..fd66c1cef9b0 100644
--- a/packages/eslint-plugin/src/rules/no-non-null-assertion.ts
+++ b/packages/eslint-plugin/src/rules/no-non-null-assertion.ts
@@ -9,7 +9,7 @@ import {
NullThrowsReasons,
} from '../util';
-type MessageIds = 'noNonNull' | 'suggestOptionalChain';
+export type MessageIds = 'noNonNull' | 'suggestOptionalChain';
export default createRule<[], MessageIds>({
name: 'no-non-null-assertion',
diff --git a/packages/eslint-plugin/src/rules/no-redeclare.ts b/packages/eslint-plugin/src/rules/no-redeclare.ts
index 99051a7b463f..841f36323e03 100644
--- a/packages/eslint-plugin/src/rules/no-redeclare.ts
+++ b/packages/eslint-plugin/src/rules/no-redeclare.ts
@@ -5,8 +5,11 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { createRule, getNameLocationInGlobalDirectiveComment } from '../util';
-type MessageIds = 'redeclared' | 'redeclaredAsBuiltin' | 'redeclaredBySyntax';
-type Options = [
+export type MessageIds =
+ | 'redeclared'
+ | 'redeclaredAsBuiltin'
+ | 'redeclaredBySyntax';
+export type Options = [
{
builtinGlobals?: boolean;
ignoreDeclarationMerge?: boolean;
diff --git a/packages/eslint-plugin/src/rules/no-require-imports.ts b/packages/eslint-plugin/src/rules/no-require-imports.ts
index 26dcbcd6c821..3836e06f82a4 100644
--- a/packages/eslint-plugin/src/rules/no-require-imports.ts
+++ b/packages/eslint-plugin/src/rules/no-require-imports.ts
@@ -4,13 +4,13 @@ import { AST_NODE_TYPES, ASTUtils } from '@typescript-eslint/utils';
import * as util from '../util';
-type Options = [
+export type Options = [
{
allow?: string[];
allowAsImport?: boolean;
},
];
-type MessageIds = 'noRequireImports';
+export type MessageIds = 'noRequireImports';
export default util.createRule({
name: 'no-require-imports',
diff --git a/packages/eslint-plugin/src/rules/no-restricted-types.ts b/packages/eslint-plugin/src/rules/no-restricted-types.ts
index b4d9e427c07f..51ffd0032eb4 100644
--- a/packages/eslint-plugin/src/rules/no-restricted-types.ts
+++ b/packages/eslint-plugin/src/rules/no-restricted-types.ts
@@ -4,7 +4,7 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { createRule, objectReduceKey } from '../util';
-type Types = Record<
+export type Types = Record<
string,
| boolean
| string
diff --git a/packages/eslint-plugin/src/rules/no-shadow.ts b/packages/eslint-plugin/src/rules/no-shadow.ts
index 6a3605e79b8e..7827954cbc45 100644
--- a/packages/eslint-plugin/src/rules/no-shadow.ts
+++ b/packages/eslint-plugin/src/rules/no-shadow.ts
@@ -6,8 +6,8 @@ import { AST_NODE_TYPES, ASTUtils } from '@typescript-eslint/utils';
import { createRule } from '../util';
import { isTypeImport } from '../util/isTypeImport';
-type MessageIds = 'noShadow' | 'noShadowGlobal';
-type Options = [
+export type MessageIds = 'noShadow' | 'noShadowGlobal';
+export type Options = [
{
allow?: string[];
builtinGlobals?: boolean;
diff --git a/packages/eslint-plugin/src/rules/no-this-alias.ts b/packages/eslint-plugin/src/rules/no-this-alias.ts
index 842b6bb6edf9..3db6a87ef932 100644
--- a/packages/eslint-plugin/src/rules/no-this-alias.ts
+++ b/packages/eslint-plugin/src/rules/no-this-alias.ts
@@ -4,13 +4,13 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { createRule } from '../util';
-type Options = [
+export type Options = [
{
allowDestructuring?: boolean;
allowedNames?: string[];
},
];
-type MessageIds = 'thisAssignment' | 'thisDestructure';
+export type MessageIds = 'thisAssignment' | 'thisDestructure';
export default createRule({
name: 'no-this-alias',
diff --git a/packages/eslint-plugin/src/rules/no-type-alias.ts b/packages/eslint-plugin/src/rules/no-type-alias.ts
index f06d5aa94202..f63b74c69964 100644
--- a/packages/eslint-plugin/src/rules/no-type-alias.ts
+++ b/packages/eslint-plugin/src/rules/no-type-alias.ts
@@ -4,14 +4,14 @@ import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils';
import { createRule } from '../util';
-type Values =
+export type Values =
| 'always'
| 'in-intersections'
| 'in-unions'
| 'in-unions-and-intersections'
| 'never';
-type Options = [
+export type Options = [
{
allowAliases?: Values;
allowCallbacks?: 'always' | 'never';
@@ -23,7 +23,7 @@ type Options = [
allowTupleTypes?: Values;
},
];
-type MessageIds = 'noCompositionAlias' | 'noTypeAlias';
+export type MessageIds = 'noCompositionAlias' | 'noTypeAlias';
type CompositionType =
| AST_NODE_TYPES.TSIntersectionType
diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-boolean-literal-compare.ts b/packages/eslint-plugin/src/rules/no-unnecessary-boolean-literal-compare.ts
index 069055d67add..cfc34d47b23e 100644
--- a/packages/eslint-plugin/src/rules/no-unnecessary-boolean-literal-compare.ts
+++ b/packages/eslint-plugin/src/rules/no-unnecessary-boolean-literal-compare.ts
@@ -11,14 +11,14 @@ import {
isStrongPrecedenceNode,
} from '../util';
-type MessageIds =
+export type MessageIds =
| 'comparingNullableToFalse'
| 'comparingNullableToTrueDirect'
| 'comparingNullableToTrueNegated'
| 'direct'
| 'negated';
-type Options = [
+export type Options = [
{
allowComparingNullableBooleansToFalse?: boolean;
allowComparingNullableBooleansToTrue?: boolean;
diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-template-expression.ts b/packages/eslint-plugin/src/rules/no-unnecessary-template-expression.ts
index 90ad42fb0169..898ab2c38220 100644
--- a/packages/eslint-plugin/src/rules/no-unnecessary-template-expression.ts
+++ b/packages/eslint-plugin/src/rules/no-unnecessary-template-expression.ts
@@ -15,7 +15,7 @@ import {
} from '../util';
import { rangeToLoc } from '../util/rangeToLoc';
-type MessageId = 'noUnnecessaryTemplateExpression';
+export type MessageId = 'noUnnecessaryTemplateExpression';
const evenNumOfBackslashesRegExp = /(?({
name: 'no-unnecessary-type-arguments',
diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts
index c73d8717c3e1..ba8b8be80b60 100644
--- a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts
+++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts
@@ -19,12 +19,12 @@ import {
NullThrowsReasons,
} from '../util';
-type Options = [
+export type Options = [
{
typesToIgnore?: string[];
},
];
-type MessageIds = 'contextuallyUnnecessary' | 'unnecessaryAssertion';
+export type MessageIds = 'contextuallyUnnecessary' | 'unnecessaryAssertion';
export default createRule({
name: 'no-unnecessary-type-assertion',
diff --git a/packages/eslint-plugin/src/rules/no-unsafe-argument.ts b/packages/eslint-plugin/src/rules/no-unsafe-argument.ts
index 60a3e01a9d51..4ae7f4bcc28b 100644
--- a/packages/eslint-plugin/src/rules/no-unsafe-argument.ts
+++ b/packages/eslint-plugin/src/rules/no-unsafe-argument.ts
@@ -14,7 +14,7 @@ import {
nullThrows,
} from '../util';
-type MessageIds =
+export type MessageIds =
| 'unsafeArgument'
| 'unsafeArraySpread'
| 'unsafeSpread'
diff --git a/packages/eslint-plugin/src/rules/no-unsafe-call.ts b/packages/eslint-plugin/src/rules/no-unsafe-call.ts
index 2c29caa2c9e1..a1f665518eaa 100644
--- a/packages/eslint-plugin/src/rules/no-unsafe-call.ts
+++ b/packages/eslint-plugin/src/rules/no-unsafe-call.ts
@@ -11,7 +11,7 @@ import {
isTypeAnyType,
} from '../util';
-type MessageIds =
+export type MessageIds =
| 'unsafeCall'
| 'unsafeCallThis'
| 'unsafeNew'
diff --git a/packages/eslint-plugin/src/rules/no-unsafe-unary-minus.ts b/packages/eslint-plugin/src/rules/no-unsafe-unary-minus.ts
index fcfca3145db6..1dd4becd1875 100644
--- a/packages/eslint-plugin/src/rules/no-unsafe-unary-minus.ts
+++ b/packages/eslint-plugin/src/rules/no-unsafe-unary-minus.ts
@@ -3,8 +3,8 @@ import * as ts from 'typescript';
import * as util from '../util';
-type Options = [];
-type MessageIds = 'unaryMinus';
+export type Options = [];
+export type MessageIds = 'unaryMinus';
export default util.createRule({
name: 'no-unsafe-unary-minus',
diff --git a/packages/eslint-plugin/src/rules/no-unused-expressions.ts b/packages/eslint-plugin/src/rules/no-unused-expressions.ts
index 8c28b5cfb8d8..8496ceee707d 100644
--- a/packages/eslint-plugin/src/rules/no-unused-expressions.ts
+++ b/packages/eslint-plugin/src/rules/no-unused-expressions.ts
@@ -10,8 +10,8 @@ import { getESLintCoreRule } from '../util/getESLintCoreRule';
const baseRule = getESLintCoreRule('no-unused-expressions');
-type MessageIds = InferMessageIdsTypeFromRule;
-type Options = InferOptionsTypeFromRule;
+export type MessageIds = InferMessageIdsTypeFromRule;
+export type Options = InferOptionsTypeFromRule;
const defaultOptions: Options = [
{
diff --git a/packages/eslint-plugin/src/rules/no-use-before-define.ts b/packages/eslint-plugin/src/rules/no-use-before-define.ts
index 712ccff66369..fa5252a7ea71 100644
--- a/packages/eslint-plugin/src/rules/no-use-before-define.ts
+++ b/packages/eslint-plugin/src/rules/no-use-before-define.ts
@@ -3,7 +3,7 @@ import type { TSESTree } from '@typescript-eslint/utils';
import { DefinitionType } from '@typescript-eslint/scope-manager';
import { AST_NODE_TYPES, TSESLint } from '@typescript-eslint/utils';
-import { createRule } from '../util';
+import { createRule, isNodeInside } from '../util';
import { referenceContainsTypeQuery } from '../util/referenceContainsTypeQuery';
const SENTINEL_TYPE =
@@ -144,10 +144,7 @@ function isClassRefInClassDecorator(
}
for (const deco of variable.defs[0].node.decorators) {
- if (
- reference.identifier.range[0] >= deco.range[0] &&
- reference.identifier.range[1] <= deco.range[1]
- ) {
+ if (isNodeInside(reference.identifier, deco)) {
return true;
}
}
@@ -203,7 +200,7 @@ function isInInitializer(
return false;
}
-interface Config {
+export interface Config {
allowNamedExports?: boolean;
classes?: boolean;
enums?: boolean;
@@ -212,8 +209,8 @@ interface Config {
typedefs?: boolean;
variables?: boolean;
}
-type Options = ['nofunc' | Config];
-type MessageIds = 'noUseBeforeDefine';
+export type Options = ['nofunc' | Config];
+export type MessageIds = 'noUseBeforeDefine';
export default createRule({
name: 'no-use-before-define',
diff --git a/packages/eslint-plugin/src/rules/no-useless-constructor.ts b/packages/eslint-plugin/src/rules/no-useless-constructor.ts
index a91525ab742c..785cdbf8547c 100644
--- a/packages/eslint-plugin/src/rules/no-useless-constructor.ts
+++ b/packages/eslint-plugin/src/rules/no-useless-constructor.ts
@@ -12,8 +12,8 @@ import { getESLintCoreRule } from '../util/getESLintCoreRule';
const baseRule = getESLintCoreRule('no-useless-constructor');
-type Options = InferOptionsTypeFromRule;
-type MessageIds = InferMessageIdsTypeFromRule;
+export type Options = InferOptionsTypeFromRule;
+export type MessageIds = InferMessageIdsTypeFromRule;
/**
* Check if method with accessibility is not useless
diff --git a/packages/eslint-plugin/src/rules/no-var-requires.ts b/packages/eslint-plugin/src/rules/no-var-requires.ts
index 19fcd3795294..d677f35c3329 100644
--- a/packages/eslint-plugin/src/rules/no-var-requires.ts
+++ b/packages/eslint-plugin/src/rules/no-var-requires.ts
@@ -4,12 +4,12 @@ import { AST_NODE_TYPES, ASTUtils } from '@typescript-eslint/utils';
import { createRule, getStaticStringValue } from '../util';
-type Options = [
+export type Options = [
{
allow: string[];
},
];
-type MessageIds = 'noVarReqs';
+export type MessageIds = 'noVarReqs';
export default createRule({
name: 'no-var-requires',
diff --git a/packages/eslint-plugin/src/rules/only-throw-error.ts b/packages/eslint-plugin/src/rules/only-throw-error.ts
index 87f6a1e34152..ada9779653a3 100644
--- a/packages/eslint-plugin/src/rules/only-throw-error.ts
+++ b/packages/eslint-plugin/src/rules/only-throw-error.ts
@@ -15,9 +15,9 @@ import {
typeOrValueSpecifiersSchema,
} from '../util';
-type MessageIds = 'object' | 'undef';
+export type MessageIds = 'object' | 'undef';
-type Options = [
+export type Options = [
{
allow?: TypeOrValueSpecifier[];
allowThrowingAny?: boolean;
diff --git a/packages/eslint-plugin/src/rules/parameter-properties.ts b/packages/eslint-plugin/src/rules/parameter-properties.ts
index 227f30abc014..cfd4323be0b6 100644
--- a/packages/eslint-plugin/src/rules/parameter-properties.ts
+++ b/packages/eslint-plugin/src/rules/parameter-properties.ts
@@ -4,7 +4,7 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { createRule, nullThrows } from '../util';
-type Modifier =
+export type Modifier =
| 'private'
| 'private readonly'
| 'protected'
@@ -13,16 +13,16 @@ type Modifier =
| 'public readonly'
| 'readonly';
-type Prefer = 'class-property' | 'parameter-property';
+export type Prefer = 'class-property' | 'parameter-property';
-type Options = [
+export type Options = [
{
allow?: Modifier[];
prefer?: Prefer;
},
];
-type MessageIds = 'preferClassProperty' | 'preferParameterProperty';
+export type MessageIds = 'preferClassProperty' | 'preferParameterProperty';
export default createRule({
name: 'parameter-properties',
diff --git a/packages/eslint-plugin/src/rules/prefer-destructuring.ts b/packages/eslint-plugin/src/rules/prefer-destructuring.ts
index 9ad46867a946..ee4f61767dbe 100644
--- a/packages/eslint-plugin/src/rules/prefer-destructuring.ts
+++ b/packages/eslint-plugin/src/rules/prefer-destructuring.ts
@@ -15,13 +15,13 @@ import { getESLintCoreRule } from '../util/getESLintCoreRule';
const baseRule = getESLintCoreRule('prefer-destructuring');
-type BaseOptions = InferOptionsTypeFromRule;
-type EnforcementOptions = {
+export type BaseOptions = InferOptionsTypeFromRule;
+export type EnforcementOptions = {
enforceForDeclarationWithTypeAnnotation?: boolean;
} & BaseOptions[1];
-type Options = [BaseOptions[0], EnforcementOptions];
+export type Options = [BaseOptions[0], EnforcementOptions];
-type MessageIds = InferMessageIdsTypeFromRule;
+export type MessageIds = InferMessageIdsTypeFromRule;
const destructuringTypeConfig: JSONSchema4 = {
type: 'object',
diff --git a/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts b/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts
index 00dae8cccb96..a339a3232045 100644
--- a/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts
+++ b/packages/eslint-plugin/src/rules/prefer-enum-initializers.ts
@@ -2,7 +2,7 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { createRule } from '../util';
-type MessageIds = 'defineInitializer' | 'defineInitializerSuggestion';
+export type MessageIds = 'defineInitializer' | 'defineInitializerSuggestion';
export default createRule<[], MessageIds>({
name: 'prefer-enum-initializers',
diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/compareNodes.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/compareNodes.ts
index 8cbc5469f0d7..932b2af5523e 100644
--- a/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/compareNodes.ts
+++ b/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/compareNodes.ts
@@ -120,7 +120,7 @@ function compareByVisiting(
return NodeComparisonResult.Equal;
}
-type CompareNodesArgument = TSESTree.Node | null | undefined;
+export type CompareNodesArgument = TSESTree.Node | null | undefined;
function compareNodesUncached(
nodeA: TSESTree.Node,
nodeB: TSESTree.Node,
diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/gatherLogicalOperands.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/gatherLogicalOperands.ts
index c0f460259707..a0a42ed94419 100644
--- a/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/gatherLogicalOperands.ts
+++ b/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/gatherLogicalOperands.ts
@@ -58,7 +58,7 @@ export interface ValidOperand {
export interface InvalidOperand {
type: OperandValidity.Invalid;
}
-type Operand = InvalidOperand | ValidOperand;
+export type Operand = InvalidOperand | ValidOperand;
const NULLISH_FLAGS = ts.TypeFlags.Null | ts.TypeFlags.Undefined;
function isValidFalseBooleanCheckType(
diff --git a/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts b/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts
index 0c90c4a4f85a..71e5efe2f74d 100644
--- a/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts
+++ b/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts
@@ -12,7 +12,7 @@ import {
readonlynessOptionsSchema,
} from '../util';
-type Options = [
+export type Options = [
{
allow?: TypeOrValueSpecifier[];
checkParameterProperties?: boolean;
@@ -20,7 +20,7 @@ type Options = [
treatMethodsAsReadonly?: boolean;
},
];
-type MessageIds = 'shouldBeReadonly';
+export type MessageIds = 'shouldBeReadonly';
export default createRule({
name: 'prefer-readonly-parameter-types',
diff --git a/packages/eslint-plugin/src/rules/prefer-readonly.ts b/packages/eslint-plugin/src/rules/prefer-readonly.ts
index 15256502ec20..a393888926cf 100644
--- a/packages/eslint-plugin/src/rules/prefer-readonly.ts
+++ b/packages/eslint-plugin/src/rules/prefer-readonly.ts
@@ -15,8 +15,8 @@ import {
getParameterPropertyHeadLoc,
} from '../util/getMemberHeadLoc';
-type MessageIds = 'preferReadonly';
-type Options = [
+export type MessageIds = 'preferReadonly';
+export type Options = [
{
onlyInlineLambdas?: boolean;
},
diff --git a/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts b/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts
index 259272d3dd37..53a9eb38c6ce 100644
--- a/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts
+++ b/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts
@@ -18,7 +18,7 @@ import {
const EQ_OPERATORS = /^[=!]=/;
const regexpp = new RegExpParser();
-type AllowedSingleElementEquality = 'always' | 'never';
+export type AllowedSingleElementEquality = 'always' | 'never';
export type Options = [
{
@@ -26,7 +26,7 @@ export type Options = [
},
];
-type MessageIds = 'preferEndsWith' | 'preferStartsWith';
+export type MessageIds = 'preferEndsWith' | 'preferStartsWith';
export default createRule({
name: 'prefer-string-starts-ends-with',
diff --git a/packages/eslint-plugin/src/rules/prefer-ts-expect-error.ts b/packages/eslint-plugin/src/rules/prefer-ts-expect-error.ts
index dc01b4a59a08..13541d4174ca 100644
--- a/packages/eslint-plugin/src/rules/prefer-ts-expect-error.ts
+++ b/packages/eslint-plugin/src/rules/prefer-ts-expect-error.ts
@@ -5,7 +5,7 @@ import { AST_TOKEN_TYPES } from '@typescript-eslint/utils';
import { createRule } from '../util';
-type MessageIds = 'preferExpectErrorComment';
+export type MessageIds = 'preferExpectErrorComment';
export default createRule<[], MessageIds>({
name: 'prefer-ts-expect-error',
diff --git a/packages/eslint-plugin/src/rules/promise-function-async.ts b/packages/eslint-plugin/src/rules/promise-function-async.ts
index d1ec3ee7f649..06fdd024c0e9 100644
--- a/packages/eslint-plugin/src/rules/promise-function-async.ts
+++ b/packages/eslint-plugin/src/rules/promise-function-async.ts
@@ -13,7 +13,7 @@ import {
NullThrowsReasons,
} from '../util';
-type Options = [
+export type Options = [
{
allowAny?: boolean;
allowedPromiseNames?: string[];
@@ -23,7 +23,7 @@ type Options = [
checkMethodDeclarations?: boolean;
},
];
-type MessageIds = 'missingAsync';
+export type MessageIds = 'missingAsync';
export default createRule({
name: 'promise-function-async',
diff --git a/packages/eslint-plugin/src/rules/require-types-exports.ts b/packages/eslint-plugin/src/rules/require-types-exports.ts
new file mode 100644
index 000000000000..67ab3c005887
--- /dev/null
+++ b/packages/eslint-plugin/src/rules/require-types-exports.ts
@@ -0,0 +1,585 @@
+import type {
+ ParserServices,
+ TSESLint,
+ TSESTree,
+} from '@typescript-eslint/utils';
+
+import {
+ ImplicitLibVariable,
+ ScopeType,
+} from '@typescript-eslint/scope-manager';
+import { AST_NODE_TYPES } from '@typescript-eslint/utils';
+import * as tsutils from 'ts-api-utils';
+import * as ts from 'typescript';
+
+import {
+ createRule,
+ findVariable,
+ getParserServices,
+ isNodeInside,
+} from '../util';
+
+export type MessageId = 'requireTypeExport' | 'requireTypeQueryExport';
+
+export default createRule({
+ name: 'require-types-exports',
+ meta: {
+ type: 'suggestion',
+ docs: {
+ description: 'Require exporting types that are used in exported entities',
+ recommended: 'strict',
+ },
+ messages: {
+ requireTypeExport:
+ '`{{ name }}` is used in exports, so it should also be exported.',
+ requireTypeQueryExport:
+ '`typeof {{ name }}` is used in exports, so `{{ name }}` and/or a standalone `typeof {{ name }}` should also be exported.',
+ },
+ schema: [],
+ },
+ defaultOptions: [],
+ create(context) {
+ const externalizedTypes = new Set();
+ const reportedNodes = new Set();
+
+ function collectImportedTypes(
+ node:
+ | TSESTree.ImportDefaultSpecifier
+ | TSESTree.ImportNamespaceSpecifier
+ | TSESTree.ImportSpecifier,
+ ) {
+ externalizedTypes.add(node.local.name);
+ }
+
+ function collectExportedTypes(node: TSESTree.Program) {
+ node.body.forEach(statement => {
+ if (
+ statement.type === AST_NODE_TYPES.ExportNamedDeclaration &&
+ statement.declaration &&
+ isCollectableType(statement.declaration) &&
+ statement.declaration.id.type === AST_NODE_TYPES.Identifier
+ ) {
+ externalizedTypes.add(statement.declaration.id.name);
+ }
+ });
+ }
+
+ function visitExportedFunctionDeclaration(
+ node: (
+ | TSESTree.ArrowFunctionExpression
+ | TSESTree.DefaultExportDeclarations
+ | TSESTree.ExportNamedDeclaration
+ ) & {
+ declaration: TSESTree.FunctionDeclaration | TSESTree.TSDeclareFunction;
+ },
+ ) {
+ checkNodeTypes(node.declaration);
+ }
+
+ function visitExportedVariableDeclaration(
+ node: TSESTree.ExportNamedDeclaration & {
+ declaration: TSESTree.VariableDeclaration;
+ },
+ ) {
+ for (const declaration of node.declaration.declarations) {
+ checkNodeTypes(declaration);
+ }
+ }
+
+ function visitExportedTypeDeclaration(
+ node: TSESTree.ExportNamedDeclaration & {
+ declaration:
+ | TSESTree.TSInterfaceDeclaration
+ | TSESTree.TSTypeAliasDeclaration;
+ },
+ ) {
+ checkNodeTypes(node.declaration);
+ }
+
+ function visitExportDefaultDeclaration(
+ node: TSESTree.ExportDefaultDeclaration,
+ ) {
+ checkNodeTypes(node.declaration);
+ }
+
+ function checkNodeTypes(node: TSESTree.Node) {
+ const { typeQueries, typeReferences } = getVisibleTypesRecursively(
+ node,
+ context.sourceCode,
+ getParserServices(context, true),
+ );
+
+ typeReferences.forEach(checkTypeReference);
+ typeQueries.forEach(checkTypeQuery);
+ }
+
+ function checkTypeReference(node: TSESTree.TSTypeReference) {
+ const name = getTypeName(node.typeName);
+ if (externalizedTypes.has(name)) {
+ return;
+ }
+
+ reportIfNeeded(name, node, 'requireTypeExport');
+ }
+
+ function checkTypeQuery(node: TSESTree.TSTypeQuery) {
+ if (node.exprName.type === AST_NODE_TYPES.TSImportType) {
+ return;
+ }
+
+ const nameQueried = getTypeName(node.exprName);
+ reportIfNeeded(nameQueried, node, 'requireTypeQueryExport');
+ }
+
+ function reportIfNeeded(
+ name: string,
+ node: TSESTree.Node,
+ messageId: MessageId,
+ ) {
+ const declaration = findVariable(context.sourceCode.getScope(node), name)
+ ?.identifiers[0];
+
+ if (!declaration || reportedNodes.has(declaration)) {
+ return;
+ }
+
+ reportedNodes.add(declaration);
+
+ if (
+ isDeclarationExported(declaration, getParserServices(context, true))
+ ) {
+ return;
+ }
+
+ context.report({
+ node: declaration,
+ messageId,
+ data: { name },
+ });
+ }
+
+ return {
+ ExportDefaultDeclaration: visitExportDefaultDeclaration,
+ 'ExportDefaultDeclaration[declaration.type="ArrowFunctionExpression"]':
+ visitExportedFunctionDeclaration,
+ 'ExportDefaultDeclaration[declaration.type="FunctionDeclaration"]':
+ visitExportedFunctionDeclaration,
+ 'ExportNamedDeclaration[declaration.type="FunctionDeclaration"]':
+ visitExportedFunctionDeclaration,
+ 'ExportNamedDeclaration[declaration.type="TSDeclareFunction"]':
+ visitExportedFunctionDeclaration,
+ 'ExportNamedDeclaration[declaration.type="TSInterfaceDeclaration"]':
+ visitExportedTypeDeclaration,
+ 'ExportNamedDeclaration[declaration.type="TSModuleDeclaration"] > ExportNamedDeclaration[declaration.type="TSInterfaceDeclaration"]':
+ visitExportedTypeDeclaration,
+ 'ExportNamedDeclaration[declaration.type="TSTypeAliasDeclaration"]':
+ visitExportedTypeDeclaration,
+ 'ExportNamedDeclaration[declaration.type="TSTypeAliasDeclaration"] > ExportNamedDeclaration[declaration.type="TSInterfaceDeclaration"]':
+ visitExportedTypeDeclaration,
+ 'ExportNamedDeclaration[declaration.type="VariableDeclaration"]':
+ visitExportedVariableDeclaration,
+ 'ImportDeclaration ImportDefaultSpecifier': collectImportedTypes,
+ 'ImportDeclaration ImportNamespaceSpecifier': collectImportedTypes,
+ 'ImportDeclaration ImportSpecifier': collectImportedTypes,
+ Program: collectExportedTypes,
+ };
+ },
+});
+
+function getLeftmostIdentifier(
+ node: TSESTree.EntityName | TSESTree.TSImportType | TSESTree.TSTypeReference,
+) {
+ switch (node.type) {
+ case AST_NODE_TYPES.Identifier:
+ return node.name;
+
+ case AST_NODE_TYPES.TSQualifiedName:
+ return getLeftmostIdentifier(node.left);
+
+ default:
+ return undefined;
+ }
+}
+
+function getTypeName(node: TSESTree.EntityName): string {
+ switch (node.type) {
+ case AST_NODE_TYPES.Identifier:
+ return node.name;
+
+ case AST_NODE_TYPES.TSQualifiedName:
+ // Namespaced types such as enums are not exported directly,
+ // so we check the leftmost part of the name.
+ return getTypeName(node.left);
+
+ case AST_NODE_TYPES.ThisExpression:
+ return 'this';
+ }
+}
+
+interface VisibleTypes {
+ typeReferences: Set;
+ typeQueries: Set;
+}
+
+function getVisibleTypesRecursively(
+ node: TSESTree.Node,
+ sourceCode: TSESLint.SourceCode,
+ services: ParserServices,
+): VisibleTypes {
+ const typeReferences = new Set();
+ const typeQueries = new Set();
+ const visited = new Set();
+
+ collect(node);
+
+ function collect(child: TSESTree.Node | null | undefined) {
+ if (!child || visited.has(child)) {
+ return;
+ }
+
+ visited.add(child);
+
+ switch (child.type) {
+ case AST_NODE_TYPES.VariableDeclarator:
+ collect(child.id);
+ collect(child.init);
+ break;
+
+ case AST_NODE_TYPES.Identifier: {
+ collect(child.typeAnnotation?.typeAnnotation);
+
+ // Resolve the variable to its declaration (in cases where the variable is referenced)
+ const scope = sourceCode.getScope(child);
+ const variableNode = findVariable(scope, child.name);
+
+ variableNode?.defs.forEach(def => {
+ collect(def.name);
+ collect(def.node);
+ });
+ break;
+ }
+
+ case AST_NODE_TYPES.ObjectExpression:
+ child.properties.forEach(property => {
+ const nodeToCheck =
+ property.type === AST_NODE_TYPES.Property
+ ? property.value
+ : property.argument;
+
+ collect(nodeToCheck);
+ });
+ break;
+
+ case AST_NODE_TYPES.ArrayExpression:
+ child.elements.forEach(element => {
+ const nodeToCheck =
+ element?.type === AST_NODE_TYPES.SpreadElement
+ ? element.argument
+ : element;
+
+ collect(nodeToCheck);
+ });
+ break;
+
+ case AST_NODE_TYPES.NewExpression:
+ case AST_NODE_TYPES.CallExpression:
+ collect(child.callee);
+ child.typeArguments?.params.forEach(collect);
+ break;
+
+ case AST_NODE_TYPES.BinaryExpression:
+ case AST_NODE_TYPES.LogicalExpression:
+ collect(child.left);
+ collect(child.right);
+ break;
+
+ case AST_NODE_TYPES.ConditionalExpression:
+ collect(child.consequent);
+ collect(child.alternate);
+ break;
+
+ case AST_NODE_TYPES.ArrowFunctionExpression:
+ case AST_NODE_TYPES.FunctionDeclaration:
+ case AST_NODE_TYPES.FunctionExpression:
+ case AST_NODE_TYPES.TSDeclareFunction:
+ child.typeParameters?.params.forEach(param =>
+ collect(param.constraint),
+ );
+ child.params.forEach(collect);
+ collect(child.returnType?.typeAnnotation);
+
+ if (child.body) {
+ collectFunctionReturnStatements(child, services).forEach(collect);
+ }
+ break;
+
+ case AST_NODE_TYPES.AssignmentPattern:
+ collect(child.left);
+ break;
+
+ case AST_NODE_TYPES.RestElement:
+ collect(child.argument);
+ collect(child.typeAnnotation?.typeAnnotation);
+ break;
+
+ case AST_NODE_TYPES.ObjectPattern:
+ child.properties.forEach(collect);
+ collect(child.typeAnnotation?.typeAnnotation);
+ break;
+
+ case AST_NODE_TYPES.ArrayPattern:
+ child.elements.forEach(collect);
+ collect(child.typeAnnotation?.typeAnnotation);
+
+ break;
+
+ case AST_NODE_TYPES.ReturnStatement:
+ collect(child.argument);
+ break;
+
+ case AST_NODE_TYPES.TSTypeReference: {
+ const scope = sourceCode.getScope(child);
+ const variable = findVariable(scope, getTypeName(child.typeName));
+
+ const isBuiltinType = variable instanceof ImplicitLibVariable;
+
+ const isGenericTypeArg =
+ (variable?.scope.type === ScopeType.function ||
+ variable?.scope.type === ScopeType.type) &&
+ variable.identifiers.every(
+ id => id.parent.type === AST_NODE_TYPES.TSTypeParameter,
+ );
+
+ if (!isBuiltinType && !isGenericTypeArg) {
+ typeReferences.add(child);
+ }
+
+ child.typeArguments?.params.forEach(collect);
+ break;
+ }
+
+ case AST_NODE_TYPES.TSTypeOperator:
+ collect(child.typeAnnotation);
+ break;
+
+ case AST_NODE_TYPES.TSTypeQuery:
+ if (
+ isInsideFunctionDeclaration(child) &&
+ !isReferencedNameInside(child.exprName, node, sourceCode)
+ ) {
+ typeQueries.add(child);
+ }
+
+ break;
+
+ case AST_NODE_TYPES.TSArrayType:
+ collect(child.elementType);
+ break;
+
+ case AST_NODE_TYPES.TSTupleType:
+ child.elementTypes.forEach(collect);
+ break;
+
+ case AST_NODE_TYPES.TSUnionType:
+ case AST_NODE_TYPES.TSIntersectionType:
+ child.types.forEach(collect);
+ break;
+
+ case AST_NODE_TYPES.TSTypeLiteral:
+ child.members.forEach(collect);
+ break;
+
+ case AST_NODE_TYPES.TSTemplateLiteralType:
+ child.types.forEach(collect);
+ break;
+
+ case AST_NODE_TYPES.TSTypeAliasDeclaration:
+ collect(child.typeAnnotation);
+ break;
+
+ case AST_NODE_TYPES.TSInterfaceDeclaration:
+ child.body.body.forEach(collect);
+ break;
+
+ case AST_NODE_TYPES.TSPropertySignature:
+ collect(child.typeAnnotation?.typeAnnotation);
+ break;
+
+ case AST_NODE_TYPES.TSQualifiedName:
+ collect(child.parent);
+ break;
+
+ case AST_NODE_TYPES.TSAsExpression:
+ collect(child.expression);
+ collect(child.typeAnnotation);
+ break;
+
+ case AST_NODE_TYPES.TSIndexedAccessType:
+ collect(child.objectType);
+ collect(child.indexType);
+ break;
+ }
+ }
+
+ return {
+ typeQueries,
+ typeReferences,
+ };
+}
+
+const collectibleNodeTypes = new Set([
+ AST_NODE_TYPES.TSTypeAliasDeclaration,
+ AST_NODE_TYPES.TSInterfaceDeclaration,
+ AST_NODE_TYPES.TSEnumDeclaration,
+ AST_NODE_TYPES.TSModuleDeclaration,
+]);
+
+function isCollectableType(
+ node: TSESTree.Node,
+): node is
+ | TSESTree.TSEnumDeclaration
+ | TSESTree.TSInterfaceDeclaration
+ | TSESTree.TSModuleDeclaration
+ | TSESTree.TSTypeAliasDeclaration {
+ return collectibleNodeTypes.has(node.type);
+}
+
+const exportNodeTypes = new Set([
+ AST_NODE_TYPES.ExportDefaultDeclaration,
+ AST_NODE_TYPES.ExportNamedDeclaration,
+ AST_NODE_TYPES.ExportAllDeclaration,
+]);
+
+function isDeclarationExported(
+ declaration: TSESTree.Node & { parent: TSESTree.Node },
+ services: ParserServices,
+) {
+ if (exportNodeTypes.has(declaration.parent.type)) {
+ return true;
+ }
+
+ if (
+ declaration.parent.type === AST_NODE_TYPES.Program ||
+ tsutils.isBlockLike(services.esTreeNodeToTSNodeMap.get(declaration.parent))
+ ) {
+ return false;
+ }
+
+ return isDeclarationExported(declaration.parent, services);
+}
+
+const functionNodeTypes = new Set([
+ AST_NODE_TYPES.ArrowFunctionExpression,
+ AST_NODE_TYPES.FunctionDeclaration,
+ AST_NODE_TYPES.FunctionExpression,
+ AST_NODE_TYPES.TSDeclareFunction,
+]);
+
+function isInsideFunctionDeclaration(node: TSESTree.Node): boolean {
+ if (!node.parent) {
+ return false;
+ }
+
+ if (functionNodeTypes.has(node.parent.type)) {
+ return true;
+ }
+
+ return isInsideFunctionDeclaration(node.parent);
+}
+
+function getDeclarationForName(
+ node: TSESTree.Node,
+ name: string,
+ sourceCode: TSESLint.SourceCode,
+) {
+ return sourceCode.getScope(node).set.get(name)?.identifiers.at(0);
+}
+
+function isReferencedNameInside(
+ child: TSESTree.EntityName | TSESTree.TSImportType,
+ parent: TSESTree.Node,
+ sourceCode: TSESLint.SourceCode,
+) {
+ const localName = getLeftmostIdentifier(child);
+ if (!localName) {
+ return false;
+ }
+
+ const declaration = getDeclarationForName(child, localName, sourceCode);
+
+ return !!declaration && isNodeInside(declaration, parent);
+}
+
+// TODO: This will have to use type information :(
+function collectFunctionReturnStatements(
+ functionNode:
+ | TSESTree.ArrowFunctionExpression
+ | TSESTree.FunctionDeclaration
+ | TSESTree.FunctionExpression,
+ services: ParserServices,
+): Set {
+ const isArrowFunctionReturn =
+ functionNode.type === AST_NODE_TYPES.ArrowFunctionExpression &&
+ functionNode.body.type !== AST_NODE_TYPES.BlockStatement;
+
+ if (isArrowFunctionReturn) {
+ return new Set([functionNode.body]);
+ }
+
+ const returnStatements = new Set();
+
+ forEachReturnStatement(functionNode, returnNode =>
+ returnStatements.add(returnNode),
+ );
+
+ return returnStatements;
+}
+
+// Heavily inspired by:
+// https://github.com/typescript-eslint/typescript-eslint/blob/103de6eed/packages/eslint-plugin/src/util/astUtils.ts#L47-L80
+function forEachReturnStatement(
+ functionNode:
+ | TSESTree.ArrowFunctionExpression
+ | TSESTree.FunctionDeclaration
+ | TSESTree.FunctionExpression,
+ visitor: (returnNode: TSESTree.ReturnStatement) => void,
+): void {
+ return traverse(functionNode.body);
+
+ function traverse(node: TSESTree.Node | null): void {
+ switch (node?.type) {
+ case AST_NODE_TYPES.ReturnStatement:
+ return visitor(node);
+
+ case AST_NODE_TYPES.SwitchStatement:
+ return node.cases.forEach(traverse);
+
+ case AST_NODE_TYPES.SwitchCase:
+ return node.consequent.forEach(traverse);
+
+ case AST_NODE_TYPES.BlockStatement:
+ return node.body.forEach(traverse);
+
+ case AST_NODE_TYPES.DoWhileStatement:
+ case AST_NODE_TYPES.ForInStatement:
+ case AST_NODE_TYPES.ForOfStatement:
+ case AST_NODE_TYPES.WhileStatement:
+ case AST_NODE_TYPES.ForStatement:
+ case AST_NODE_TYPES.WithStatement:
+ case AST_NODE_TYPES.CatchClause:
+ case AST_NODE_TYPES.LabeledStatement:
+ return traverse(node.body);
+
+ case AST_NODE_TYPES.IfStatement:
+ traverse(node.consequent);
+ traverse(node.alternate);
+ return;
+
+ case AST_NODE_TYPES.TryStatement:
+ traverse(node.block);
+ traverse(node.handler);
+ traverse(node.finalizer);
+ return;
+ }
+ }
+}
diff --git a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts
index 306342754018..f7b8e2f6a15d 100644
--- a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts
+++ b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts
@@ -12,7 +12,7 @@ import {
isTypeFlagSet,
} from '../util';
-type Options = [
+export type Options = [
{
allowAny?: boolean;
allowBoolean?: boolean;
@@ -23,7 +23,7 @@ type Options = [
},
];
-type MessageIds = 'bigintAndNumber' | 'invalid' | 'mismatched';
+export type MessageIds = 'bigintAndNumber' | 'invalid' | 'mismatched';
export default createRule({
name: 'restrict-plus-operands',
diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts
index 3049c1fe3fcf..06c071520c0e 100644
--- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts
+++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts
@@ -56,13 +56,13 @@ const optionTesters = (
option: `allow${type}` as const,
tester,
}));
-type Options = [
+export type Options = [
{
allow?: TypeOrValueSpecifier[];
} & Partial>,
];
-type MessageId = 'invalidType';
+export type MessageId = 'invalidType';
export default createRule({
name: 'restrict-template-expressions',
diff --git a/packages/eslint-plugin/src/rules/switch-exhaustiveness-check.ts b/packages/eslint-plugin/src/rules/switch-exhaustiveness-check.ts
index 1323344605c8..316770b6b131 100644
--- a/packages/eslint-plugin/src/rules/switch-exhaustiveness-check.ts
+++ b/packages/eslint-plugin/src/rules/switch-exhaustiveness-check.ts
@@ -23,7 +23,7 @@ interface SwitchMetadata {
readonly symbolName: string | undefined;
}
-type Options = [
+export type Options = [
{
/**
* If `true`, allow `default` cases on switch statements with exhaustive
@@ -54,7 +54,7 @@ type Options = [
},
];
-type MessageIds =
+export type MessageIds =
| 'addMissingCases'
| 'dangerousDefaultCase'
| 'switchIsNotExhaustive';
diff --git a/packages/eslint-plugin/src/rules/triple-slash-reference.ts b/packages/eslint-plugin/src/rules/triple-slash-reference.ts
index d7908e7273b0..79c40ac37782 100644
--- a/packages/eslint-plugin/src/rules/triple-slash-reference.ts
+++ b/packages/eslint-plugin/src/rules/triple-slash-reference.ts
@@ -4,14 +4,14 @@ import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils';
import { createRule } from '../util';
-type Options = [
+export type Options = [
{
lib?: 'always' | 'never';
path?: 'always' | 'never';
types?: 'always' | 'never' | 'prefer-import';
},
];
-type MessageIds = 'tripleSlashReference';
+export type MessageIds = 'tripleSlashReference';
export default createRule({
name: 'triple-slash-reference',
diff --git a/packages/eslint-plugin/src/rules/typedef.ts b/packages/eslint-plugin/src/rules/typedef.ts
index dd70a97706ec..a1b61c00c20a 100644
--- a/packages/eslint-plugin/src/rules/typedef.ts
+++ b/packages/eslint-plugin/src/rules/typedef.ts
@@ -4,7 +4,7 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { createRule } from '../util';
-const enum OptionKeys {
+export const enum OptionKeys {
ArrayDestructuring = 'arrayDestructuring',
ArrowParameter = 'arrowParameter',
MemberVariableDeclaration = 'memberVariableDeclaration',
@@ -15,9 +15,9 @@ const enum OptionKeys {
VariableDeclarationIgnoreFunction = 'variableDeclarationIgnoreFunction',
}
-type Options = Partial>;
+export type Options = Partial>;
-type MessageIds = 'expectedTypedef' | 'expectedTypedefNamed';
+export type MessageIds = 'expectedTypedef' | 'expectedTypedefNamed';
export default createRule<[Options], MessageIds>({
name: 'typedef',
diff --git a/packages/eslint-plugin/src/rules/unbound-method.ts b/packages/eslint-plugin/src/rules/unbound-method.ts
index 37e8d0868e25..455f0e66bcee 100644
--- a/packages/eslint-plugin/src/rules/unbound-method.ts
+++ b/packages/eslint-plugin/src/rules/unbound-method.ts
@@ -16,7 +16,7 @@ import {
// Rule Definition
//------------------------------------------------------------------------------
-interface Config {
+export interface Config {
ignoreStatic: boolean;
}
diff --git a/packages/eslint-plugin/src/rules/unified-signatures.ts b/packages/eslint-plugin/src/rules/unified-signatures.ts
index 130c56529a73..9c255b6f9f50 100644
--- a/packages/eslint-plugin/src/rules/unified-signatures.ts
+++ b/packages/eslint-plugin/src/rules/unified-signatures.ts
@@ -53,12 +53,12 @@ type MethodDefinition =
| TSESTree.MethodDefinition
| TSESTree.TSAbstractMethodDefinition;
-type MessageIds =
+export type MessageIds =
| 'omittingRestParameter'
| 'omittingSingleParameter'
| 'singleParameterDifference';
-type Options = [
+export type Options = [
{
ignoreDifferentlyNamedParameters?: boolean;
},
diff --git a/packages/eslint-plugin/src/rules/use-unknown-in-catch-callback-variable.ts b/packages/eslint-plugin/src/rules/use-unknown-in-catch-callback-variable.ts
index 0ee671556d13..42d311644dfd 100644
--- a/packages/eslint-plugin/src/rules/use-unknown-in-catch-callback-variable.ts
+++ b/packages/eslint-plugin/src/rules/use-unknown-in-catch-callback-variable.ts
@@ -14,7 +14,7 @@ import {
nullThrows,
} from '../util';
-type MessageIds =
+export type MessageIds =
| 'addUnknownRestTypeAnnotationSuggestion'
| 'addUnknownTypeAnnotationSuggestion'
| 'useUnknown'
diff --git a/packages/eslint-plugin/src/util/astUtils.ts b/packages/eslint-plugin/src/util/astUtils.ts
index c2450ae30130..4395056c6dfd 100644
--- a/packages/eslint-plugin/src/util/astUtils.ts
+++ b/packages/eslint-plugin/src/util/astUtils.ts
@@ -7,6 +7,13 @@ import { escapeRegExp } from './escapeRegExp';
// deeply re-export, for convenience
export * from '@typescript-eslint/utils/ast-utils';
+export function isNodeInside(
+ child: TSESTree.Node,
+ parent: TSESTree.Node,
+): boolean {
+ return child.range[0] > parent.range[0] && child.range[1] < parent.range[1];
+}
+
// The following is copied from `eslint`'s source code since it doesn't exist in eslint@5.
// https://github.com/eslint/eslint/blob/145aec1ab9052fbca96a44d04927c595951b1536/lib/rules/utils/ast-utils.js#L1751-L1779
// Could be export { getNameLocationInGlobalDirectiveComment } from 'eslint/lib/rules/utils/ast-utils'
diff --git a/packages/eslint-plugin/src/util/getESLintCoreRule.ts b/packages/eslint-plugin/src/util/getESLintCoreRule.ts
index 97bc8620b01d..e895bcb3c7bd 100644
--- a/packages/eslint-plugin/src/util/getESLintCoreRule.ts
+++ b/packages/eslint-plugin/src/util/getESLintCoreRule.ts
@@ -1,7 +1,7 @@
import { ESLintUtils } from '@typescript-eslint/utils';
import { builtinRules } from 'eslint/use-at-your-own-risk';
-interface RuleMap {
+export interface RuleMap {
/* eslint-disable @typescript-eslint/consistent-type-imports -- more concise to use inline imports */
'arrow-parens': typeof import('eslint/lib/rules/arrow-parens');
'consistent-return': typeof import('eslint/lib/rules/consistent-return');
@@ -27,7 +27,7 @@ interface RuleMap {
/* eslint-enable @typescript-eslint/consistent-type-imports */
}
-type RuleId = keyof RuleMap;
+export type RuleId = keyof RuleMap;
export const getESLintCoreRule = (ruleId: R): RuleMap[R] =>
ESLintUtils.nullThrows(
diff --git a/packages/eslint-plugin/src/util/getFunctionHeadLoc.ts b/packages/eslint-plugin/src/util/getFunctionHeadLoc.ts
index 49ab2b742dd9..ae010cad08d6 100644
--- a/packages/eslint-plugin/src/util/getFunctionHeadLoc.ts
+++ b/packages/eslint-plugin/src/util/getFunctionHeadLoc.ts
@@ -6,7 +6,7 @@ import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';
import { isArrowToken, isOpeningParenToken } from './astUtils';
-type FunctionNode =
+export type FunctionNode =
| TSESTree.ArrowFunctionExpression
| TSESTree.FunctionDeclaration
| TSESTree.FunctionExpression;
diff --git a/packages/eslint-plugin/src/util/getOperatorPrecedence.ts b/packages/eslint-plugin/src/util/getOperatorPrecedence.ts
index 950708015d89..aa4a0befb109 100644
--- a/packages/eslint-plugin/src/util/getOperatorPrecedence.ts
+++ b/packages/eslint-plugin/src/util/getOperatorPrecedence.ts
@@ -296,7 +296,7 @@ export function getOperatorPrecedenceForNode(
}
}
-type TSESTreeOperatorKind =
+export type TSESTreeOperatorKind =
| ValueOf
| ValueOf;
diff --git a/packages/eslint-plugin/src/util/getWrappingFixer.ts b/packages/eslint-plugin/src/util/getWrappingFixer.ts
index 26afcaa6405b..478cda934910 100644
--- a/packages/eslint-plugin/src/util/getWrappingFixer.ts
+++ b/packages/eslint-plugin/src/util/getWrappingFixer.ts
@@ -6,7 +6,7 @@ import {
ESLintUtils,
} from '@typescript-eslint/utils';
-interface WrappingFixerParams {
+export interface WrappingFixerParams {
/**
* Descendant of `node` we want to preserve.
* Use this to replace some code with another.
diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/require-types-exports.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/require-types-exports.shot
new file mode 100644
index 000000000000..34ec8eeaab0c
--- /dev/null
+++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/require-types-exports.shot
@@ -0,0 +1,78 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Validating rule docs require-types-exports.mdx code examples ESLint output 1`] = `
+"Incorrect
+
+interface Fruit {
+ ~~~~~ \`Fruit\` is used in exports, so it should also be exported.
+ name: string;
+ color: string;
+}
+
+export const getFruitName = (fruit: Fruit) => fruit.name;
+"
+`;
+
+exports[`Validating rule docs require-types-exports.mdx code examples ESLint output 2`] = `
+"Incorrect
+
+const fruits = {
+ ~~~~~~ \`typeof fruits\` is used in exports, so \`fruits\` and/or a standalone \`typeof fruits\` should also be exported.
+ apple: '🍏',
+ banana: '🍌',
+};
+
+export const getFruit = (key: keyof typeof fruits) => fruits[key];
+"
+`;
+
+exports[`Validating rule docs require-types-exports.mdx code examples ESLint output 3`] = `
+"Incorrect
+
+enum Color {
+ ~~~~~ \`Color\` is used in exports, so it should also be exported.
+ Red = 'red',
+ Green = 'green',
+ Blue = 'blue',
+}
+
+export declare function getRandomColor(): Color;
+"
+`;
+
+exports[`Validating rule docs require-types-exports.mdx code examples ESLint output 4`] = `
+"Correct
+
+export interface Fruit {
+ name: string;
+ color: string;
+}
+
+export const getFruitName = (fruit: Fruit) => fruit.name;
+"
+`;
+
+exports[`Validating rule docs require-types-exports.mdx code examples ESLint output 5`] = `
+"Correct
+
+export const fruits = {
+ apple: '🍏',
+ banana: '🍌',
+};
+
+export const getFruit = (key: keyof typeof fruits) => fruits[key];
+"
+`;
+
+exports[`Validating rule docs require-types-exports.mdx code examples ESLint output 6`] = `
+"Correct
+
+export enum Color {
+ Red = 'red',
+ Green = 'green',
+ Blue = 'blue',
+}
+
+export declare function getRandomColor(): Color;
+"
+`;
diff --git a/packages/eslint-plugin/tests/fixtures/tsconfig-with-dom.json b/packages/eslint-plugin/tests/fixtures/tsconfig-with-dom.json
new file mode 100644
index 000000000000..6168cfcb8d54
--- /dev/null
+++ b/packages/eslint-plugin/tests/fixtures/tsconfig-with-dom.json
@@ -0,0 +1,6 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "lib": ["esnext", "DOM"]
+ }
+}
diff --git a/packages/eslint-plugin/tests/rules/naming-convention/cases/createTestCases.ts b/packages/eslint-plugin/tests/rules/naming-convention/cases/createTestCases.ts
index 3025252d72e6..0faf3c30e892 100644
--- a/packages/eslint-plugin/tests/rules/naming-convention/cases/createTestCases.ts
+++ b/packages/eslint-plugin/tests/rules/naming-convention/cases/createTestCases.ts
@@ -82,7 +82,7 @@ const IGNORED_FILTER = {
regex: /.gnored/.source,
};
-type Cases = { code: string[]; options: Omit }[];
+export type Cases = { code: string[]; options: Omit }[];
export function createTestCases(cases: Cases): void {
const createValidTestCases = (): ValidTestCase[] =>
diff --git a/packages/eslint-plugin/tests/rules/prefer-optional-chain/base-cases.ts b/packages/eslint-plugin/tests/rules/prefer-optional-chain/base-cases.ts
index e5883c31219d..18e1b25b17f8 100644
--- a/packages/eslint-plugin/tests/rules/prefer-optional-chain/base-cases.ts
+++ b/packages/eslint-plugin/tests/rules/prefer-optional-chain/base-cases.ts
@@ -5,8 +5,8 @@ import type {
PreferOptionalChainOptions,
} from '../../../src/rules/prefer-optional-chain-utils/PreferOptionalChainOptions';
-type MutateFn = (c: string) => string;
-type BaseCaseCreator = (args: {
+export type MutateFn = (c: string) => string;
+export type BaseCaseCreator = (args: {
mutateCode?: MutateFn;
mutateDeclaration?: MutateFn;
mutateOutput?: MutateFn;
diff --git a/packages/eslint-plugin/tests/rules/require-types-exports.test.ts b/packages/eslint-plugin/tests/rules/require-types-exports.test.ts
new file mode 100644
index 000000000000..3a4ba68f6bbc
--- /dev/null
+++ b/packages/eslint-plugin/tests/rules/require-types-exports.test.ts
@@ -0,0 +1,3472 @@
+import { RuleTester } from '@typescript-eslint/rule-tester';
+
+import rule from '../../src/rules/require-types-exports';
+import { getFixturesRootDir } from '../RuleTester';
+
+const rootPath = getFixturesRootDir();
+
+const ruleTester = new RuleTester({
+ languageOptions: {
+ parserOptions: {
+ project: './tsconfig-with-dom.json',
+ tsconfigRootDir: rootPath,
+ },
+ },
+});
+
+ruleTester.run('require-types-exports', rule, {
+ valid: [
+ 'const someValue = undeclared;',
+ 'let someValue = undeclared;',
+ 'let someValue = a;',
+ 'let someValue = a();',
+ 'a();',
+ 'a.b();',
+ 'a[b]();',
+ "a['b']();",
+ "a['b'](c);",
+ 'export const a = () => b;',
+ 'export const a = () => b[0];',
+ 'export const a = () => [b];',
+ 'export const a = () => [, b];',
+ 'export const a = () => [b, ,];',
+ 'export const a = () => ({});',
+ 'export const a = () => ({ a });',
+ 'export const a = () => ({ a: a });',
+ 'export const a = () => ({ a: b });',
+
+ 'export function f(): void {}',
+ 'export const f = (): void => {};',
+
+ 'export function f(a: number): void {}',
+ 'export const f = (a: number): void => {};',
+
+ 'export function f(a: any): void {}',
+ 'export const f = (a: any): void => {};',
+
+ 'export function f(a: null): void {}',
+ 'export const f = (a: null): void => {};',
+
+ 'export function f(a: string | number): void {}',
+ 'export const f = (a: string | number): void => {};',
+
+ 'export function f(a?: string | number): void {}',
+ 'export const f = (a?: string | number): void => {};',
+
+ 'export function f(a: number): string {}',
+ 'export const f = (a: number): string => {};',
+
+ 'export function f(...args: any[]): void {}',
+ 'export const f = (...args: any[]): void => {};',
+
+ 'export function f(...args: unknown[]): void {}',
+ 'export const f = (...args: unknown[]): void => {};',
+
+ 'export function f(...args): void {}',
+ 'export const f = (...args): void => {};',
+
+ 'export default function f(): void {}',
+ 'export default (): void => {};',
+
+ `
+ function f(a: A): A {
+ return a;
+ }
+ `,
+ `
+ type A = number;
+ function f(a: A): A {
+ return a;
+ }
+ `,
+ `
+ type A = number;
+ const f = (a: A): A => a;
+ `,
+ `
+ type A = number;
+ type B = string;
+ function f(a: A | B): any {
+ return a;
+ }
+ `,
+ `
+ type A = number;
+ type B = string;
+ const f = (a: A | B): any => a;
+ `,
+ `
+ type A = number;
+ declare function f(a: A): void;
+ `,
+ `
+ type A = number;
+ function f({ a }): A {}
+ `,
+ `
+ type A = number;
+ function f({ a }: { a: A }): A {}
+ `,
+ `
+ type A = number;
+ const f = ({ a }: { a: A }): A => {};
+ `,
+ `
+ type A = number;
+ type B = string;
+ function f([a, b]: [A, B]): void {}
+ `,
+ `
+ type A = number;
+ type B = string;
+ const f = ([a, b]: [A, B]): void => {};
+ `,
+ `
+ type A = number;
+ function f(a: A): void {}
+ `,
+ `
+ type A = number;
+ const f = (a: A): void => {};
+ `,
+ `
+ interface A {
+ a: number;
+ }
+
+ function f(a: A): A {
+ return a;
+ }
+ `,
+ `
+ interface A {
+ a: number;
+ }
+
+ const f = (a: A): A => a;
+ `,
+ `
+ export type A = number;
+ export function f(a: A): void {}
+ `,
+ `
+ export type A = number;
+ export const f = (a: A): void => {};
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export function f(a: A | B): void {}
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export const f = (a: A | B): void => {};
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export function f(a: A & B): void {}
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export const f = (a: A & B): void => {};
+ `,
+ `
+ export type A = number;
+ export function f(...args: A[]): void {}
+ `,
+ `
+ export type A = number;
+ export const f = (...args: A[]): void => {};
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export function f(args: { a: A; b: B; c: number }): void {}
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export const f = (args: { a: A; b: B; c: number }): void => {};
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export function f(args: [A, B]): void {}
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export const f = (args: [A, B]): void => {};
+ `,
+ `
+ export type A = number;
+ export function f(a: A = 1): void {}
+ `,
+ `
+ export type A = number;
+ export const f = (a: A = 1): void => {};
+ `,
+ `
+ export type A = number;
+ export function f(): A {}
+ `,
+ `
+ export type A = number;
+ export const f = (): A => {};
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export function f(): A | B {}
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export const f = (): A | B => {};
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export function f(): A & B {}
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export const f = (): A & B => {};
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export function f(): [A, B] {}
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export const f = (): [A, B] => {};
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export function f(): { a: A; b: B } {}
+ `,
+ `
+ export type A = number;
+ export type B = string;
+ export const f = (): { a: A; b: B } => {};
+ `,
+ `
+ export type A = number;
+ export const f = ({ a }: { a: A }): void => {};
+ `,
+ `
+ import { testFunction, type Arg } from './module';
+
+ export function f(a: Arg): void {}
+ `,
+ `
+ import { Arg } from './types';
+
+ export function f(a: Arg): void {}
+ `,
+ `
+ import type { Arg } from './types';
+
+ export function f(a: Arg): void {}
+ `,
+ `
+ import type { ImportedArg as Arg } from './types';
+
+ export function f(a: Arg): void {}
+ `,
+ `
+ import type { Arg } from './types';
+
+ export function f(a: T): void {}
+ `,
+ `
+ export type R = number;
+
+ export function f() {
+ const value: { num: R } = {
+ num: 1,
+ };
+
+ return value;
+ }
+ `,
+ `
+ import type { A } from './types';
+
+ export type T1 = number;
+
+ export interface T2 {
+ key: number;
+ }
+
+ export const value: { a: { b: { c: T1 } } } | [string, T2 | A] = {
+ a: {
+ b: {
+ c: 1,
+ },
+ },
+ };
+ `,
+ `
+ import type { A } from './types';
+
+ export type T1 = number;
+
+ export interface T2 {
+ key: number;
+ }
+
+ const value: { a: { b: { c: T1 } } } | [string, T2 | A] = {
+ a: {
+ b: {
+ c: 1,
+ },
+ },
+ };
+
+ export default value;
+ `,
+ `
+ export enum Fruit {
+ Apple,
+ Banana,
+ Cherry,
+ }
+
+ export function f(a: Fruit): void {}
+ `,
+ `
+ export function f(arg: Record>) {
+ return arg;
+ }
+ `,
+ `
+ export function f>>(arg: T) {
+ return arg;
+ }
+ `,
+ `
+ export function f string>>(arg: T) {
+ return arg;
+ }
+ `,
+ `
+ export class Wrapper {
+ work(other: this) {}
+ }
+ `,
+ `
+ export class Wrapper {
+ work(other: typeof this) {}
+ }
+ `,
+ 'export function noop(x: this) {}',
+ 'export function noop(x: typeof this) {}',
+ `
+ export namespace A {
+ export namespace B {
+ export type C = number;
+ }
+ }
+
+ export function a(arg: A.B.C) {
+ return arg;
+ }
+ `,
+ `
+ import * as ts from 'typescript';
+
+ export function a(arg: ts.Type) {
+ return arg;
+ }
+ `,
+ `
+ import ts from 'typescript';
+
+ export function a(arg: ts.Type) {
+ return arg;
+ }
+ `,
+ `
+ declare const element: HTMLElement;
+
+ export default element;
+ `,
+ `
+ export const date: Date = new Date();
+ `,
+ `
+ import ts from 'typescript';
+
+ export enum Fruit {
+ Apple,
+ Banana,
+ Cherry,
+ }
+
+ declare const apple: Fruit.Apple;
+
+ export type A = number;
+ export type B = string;
+ export type C = boolean;
+
+ export interface D {
+ key: string;
+ }
+
+ function func>(
+ arg: T,
+ ): T | ts.Type {
+ return arg;
+ }
+
+ export const value = {
+ apple,
+ func,
+ };
+ `,
+ `
+ export function func1() {
+ return func2(1);
+ }
+
+ export type A = number;
+
+ export function func2(arg: A) {
+ return 1;
+ }
+ `,
+ 'export type ValueOf = T[keyof T];',
+
+ `
+ const fruits = { apple: 'apple' };
+ export type Fruits = typeof fruits;
+
+ export function getFruit(key: Key): Fruits[Key] {
+ return fruits[key];
+ }
+ `,
+ `
+ const fruits = { apple: 'apple' };
+
+ export function doWork(): number {
+ const fruit: keyof typeof fruits = 'apple';
+
+ return 1;
+ }
+ `,
+ `
+declare function wrap(listeners: unknown): unknown;
+
+type Abc = 'abc';
+
+export default wrap({
+ abc(input: Abc) {
+ //
+ },
+});
+ `,
+ 'export function example(config: string): typeof config {}',
+ 'export function example(config: string): typeof config.length {}',
+ "export function example(config: string): (typeof config)['length'] {}",
+ "export function example(config: string): typeof import('config') {}",
+ 'export function example(config: ExternalGlobal) {}',
+ 'export function example(config: typeof ExternalGlobal) {}',
+ 'export function example(config: typeof ExternalGlobal.length) {}',
+ "export function example(config: (typeof ExternalGlobal)['length']) {}",
+ `
+export namespace Values {
+ export type Fruit = 'apple';
+
+ export function logFruit(fruit: Fruit) {
+ console.log(fruit);
+ }
+}
+ `,
+ `
+declare module '@babel/eslint-parser' {
+ export interface Options {}
+ export function parse(options: Options): void;
+}
+ `,
+ `
+export const pairs = { KEY: 'value' } as const;
+
+export function emitDeprecationWarning(akey: keyof typeof pairs) {
+ console.log(key);
+}
+ `,
+ `
+declare function identity(input: T): T;
+
+interface Box {
+ // ...
+}
+
+export function usesType() {
+ const box: Box = {};
+ return identity(box);
+}
+ `,
+ ],
+ invalid: [
+ {
+ code: `
+ type Arg = number;
+
+ export function f(a: Arg): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ export const f = (a: Arg): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ export default function (a: Arg): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ export default (a: Arg): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ export function f(a: Arg, b: Arg): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ export const f = (a: Arg, b: Arg): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export function f(a: Arg1, b: Arg2): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export const f = (a: Arg1, b: Arg2): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+
+ interface Arg2 {
+ a: string;
+ }
+
+ export function f(a: Arg1, b: Arg2): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 19,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 23,
+ line: 4,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+
+ interface Arg2 {
+ a: string;
+ }
+
+ export const f = (a: Arg1, b: Arg2): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 19,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 23,
+ line: 4,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export function f(a: Arg1 | Arg2): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export const f = (a: Arg1 | Arg2): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export function f(a: Arg1 & Arg2): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export const f = (a: Arg1 & Arg2): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export function f([a, b]: [Arg1, Arg2, number]): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+ type Arg3 = boolean;
+
+ export function f([a, b]: [Arg1, Arg2, number], c: Arg3): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg3',
+ },
+ endColumn: 18,
+ line: 4,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export const f = ([a, b]: [Arg1, Arg2, number]): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export function f({ a, b }: { a: Arg1; b: Arg2; c: number }): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export const f = ({ a, b }: { a: Arg1; b: Arg2; c: number }): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ export function f(...args: Arg[]): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ export const f = (...args: Arg[]): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ export function f(a: Arg = 1): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ export const f = (a: Arg = 1): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ enum Fruit {
+ Apple,
+ Banana,
+ Cherry,
+ }
+
+ export function f(a: Fruit): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Fruit',
+ },
+ endColumn: 19,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ enum Fruit {
+ Apple,
+ Banana,
+ Cherry,
+ }
+
+ export const f = (a: Fruit): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Fruit',
+ },
+ endColumn: 19,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ export function f(a: T): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export function f(a: T): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export function f(a: T): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export function f(a: T): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export const f = (a: T): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = string;
+
+ export function f(a: T): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = string;
+
+ export function f(a: T): void {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret = string;
+
+ export function f(): Ret {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret = string;
+
+ export const f = (): Ret => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret1 = string;
+ type Ret2 = number;
+
+ export function f(): Ret1 | Ret2 {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret1 = string;
+ type Ret2 = number;
+
+ export const f = (): Ret1 | Ret2 => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret1 = string;
+ type Ret2 = number;
+
+ export function f(): Ret1 & Ret2 {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret1 = string;
+ type Ret2 = number;
+
+ export const f = (): Ret1 & Ret2 => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret1 = string;
+ type Ret2 = number;
+
+ export function f(): [Ret1, Ret2, number, Ret1] {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret1 = string;
+ type Ret2 = number;
+
+ export const f = (): [Ret1, Ret2, number, Ret1] => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret1 = string;
+ type Ret2 = number;
+
+ export function f(): { a: Ret1; b: Ret2; c: number; d: Ret1 } {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret1 = string;
+ type Ret2 = number;
+
+ export const f = (): { a: Ret1; b: Ret2; c: number; d: Ret1 } => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret = string;
+
+ export function f(): T {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret1 = string;
+ type Ret2 = number;
+
+ export function f(): T {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret1 = string;
+ type Ret2 = number;
+
+ export function f(): T {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret1 = string;
+ type Ret2 = number;
+
+ export function f(): T {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret1 = string;
+ type Ret2 = number;
+
+ export function f(): T {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Ret = string;
+
+ export function f(): T {}
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Ret',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ const a = (a: Arg): void => {};
+
+ export default a;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ const a = function (a: Arg): void {};
+
+ export default a;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ export declare function f(a: Arg): void;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg = number;
+
+ export declare function f(a: Arg): Arg;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg',
+ },
+ endColumn: 17,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type R = number;
+
+ export function f() {
+ const value: { num: R } = {
+ num: 1,
+ };
+
+ return value;
+ }
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'R',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = boolean;
+ type Ret = string;
+
+ export declare function f(
+ a: { b: { c: Arg1 | number | { d: T } } },
+ e: Arg1,
+ ): { a: { b: T | Ret } };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Ret',
+ },
+ endColumn: 17,
+ line: 4,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export declare function f(a: Arg1): true;
+ export declare function f(a: Arg2): false;
+ export declare function f(a: Arg1 | Arg2): boolean;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Arg1 = number;
+ type Arg2 = string;
+
+ export const f1 = (a: Arg1): void => {},
+ f2 = (a: Arg2): void => {};
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Arg1',
+ },
+ endColumn: 18,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Arg2',
+ },
+ endColumn: 18,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ namespace A {
+ export namespace B {
+ export type C = number;
+ }
+ }
+
+ export function a(arg: A.B.C) {
+ return arg;
+ }
+ `,
+ errors: [
+ {
+ column: 19,
+ data: {
+ name: 'A',
+ },
+ endColumn: 20,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ namespace A {
+ export type B = number;
+ }
+
+ type B = string;
+
+ export function a(arg: B) {
+ return arg;
+ }
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 6,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ namespace A {
+ export interface B {
+ value: number;
+ }
+ }
+
+ type B = string;
+
+ export function a(arg: B) {
+ return arg;
+ }
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 8,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ namespace A {
+ export enum B {
+ Value1,
+ Value2,
+ }
+ }
+
+ type B = string;
+
+ export function a(arg: B) {
+ return arg;
+ }
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 9,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ namespace A {
+ export namespace B {
+ export type C = number;
+ }
+ }
+
+ type B = string;
+
+ export function a(arg: B) {
+ return arg;
+ }
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 8,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ import type { A } from './types';
+
+ type T1 = number;
+
+ interface T2 {
+ key: number;
+ }
+
+ export const value: { a: { b: { c: T1 } } } | [string, T2 | A] = {
+ a: {
+ b: {
+ c: 1,
+ },
+ },
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'T1',
+ },
+ endColumn: 16,
+ line: 4,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 19,
+ data: {
+ name: 'T2',
+ },
+ endColumn: 21,
+ line: 6,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ import type { A } from './types';
+
+ type T1 = number;
+
+ interface T2 {
+ key: number;
+ }
+
+ const value: { a: { b: { c: T1 } } } | [string, T2 | A] = {
+ a: {
+ b: {
+ c: 1,
+ },
+ },
+ };
+
+ export default value;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'T1',
+ },
+ endColumn: 16,
+ line: 4,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 19,
+ data: {
+ name: 'T2',
+ },
+ endColumn: 21,
+ line: 6,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type T1 = number;
+
+ interface T2 {
+ key: number;
+ }
+
+ type T3 = boolean;
+
+ export const value:
+ | {
+ a: T1;
+ b: {
+ c: T2;
+ };
+ }
+ | T3[] = {
+ a: 1,
+ b: {
+ c: {
+ key: 1,
+ },
+ },
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'T1',
+ },
+ endColumn: 16,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 19,
+ data: {
+ name: 'T2',
+ },
+ endColumn: 21,
+ line: 4,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'T3',
+ },
+ endColumn: 16,
+ line: 8,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = string;
+ type B = string;
+
+ const apple: A = 'apple';
+ const banana: B = 'banana';
+
+ export const value = {
+ path: {
+ to: {
+ apple,
+ and: {
+ banana,
+ },
+ },
+ },
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = string;
+ type B = string;
+
+ const apple: A = 'apple';
+ const banana: B = 'banana';
+
+ const value = {
+ path: {
+ to: {
+ apple,
+ and: {
+ banana,
+ },
+ },
+ },
+ };
+
+ export default value;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = string;
+ type B = string;
+
+ const apple: A = 'apple';
+ const banana: B = 'banana';
+
+ const value = {
+ spreadObject: { ...{ apple } },
+ spreadArray: [...[banana]],
+ };
+
+ export default value;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Fruit = 'apple' | 'banana';
+
+ const apple: Fruit = 'apple';
+ const banana: Fruit = 'banana';
+
+ export const value = {
+ path: {
+ to: [apple, banana],
+ },
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Fruit',
+ },
+ endColumn: 19,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Fruit = 'apple' | 'banana';
+
+ const apple: Fruit = 'apple';
+ const banana: Fruit = 'banana';
+
+ export const value = {
+ path: {
+ to: [apple, banana] as const,
+ },
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Fruit',
+ },
+ endColumn: 19,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Fruit = 'apple' | 'banana';
+
+ const apple: Fruit = 'apple';
+ const banana: Fruit = 'banana';
+
+ export const value = {
+ path: {
+ to: [apple, banana] as any,
+ },
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Fruit',
+ },
+ endColumn: 19,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Fruit = 'apple' | 'banana';
+
+ const apple = 'apple';
+ const banana = 'banana';
+
+ export const value = {
+ path: {
+ to: [apple, banana] as [Fruit, Fruit],
+ },
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Fruit',
+ },
+ endColumn: 19,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Fruit = 'apple' | 'banana';
+
+ const apple = 'apple';
+ const banana = 'banana';
+
+ export const value = {
+ path: {
+ to: [apple, banana] as Fruit | number,
+ },
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Fruit',
+ },
+ endColumn: 19,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = string;
+ type C = boolean;
+ type D = symbol;
+
+ declare const a: [A, B] | ([Array, Set] & Exclude);
+
+ export const value = { a };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'C',
+ },
+ endColumn: 15,
+ line: 4,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'D',
+ },
+ endColumn: 15,
+ line: 5,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = string;
+
+ export const value = {
+ func: (arg: A): B => 'apple',
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = string;
+
+ export const value = {
+ func: function (arg: A): B {
+ return 'apple';
+ },
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = string;
+
+ const func = (arg: A): B => 'apple';
+
+ export const value = {
+ func,
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = string;
+
+ const func = function (arg: A): B {
+ return 'apple';
+ };
+
+ export const value = {
+ func,
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ const func = (arg: T): T => 'apple';
+
+ export const value = {
+ func,
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ const func = function (arg: T): T {
+ return 'apple';
+ };
+
+ export const value = {
+ func,
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ export const value = {
+ func: (arg: T): T => 'apple',
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ export const value = {
+ func: function (arg: T): T {
+ return 'apple';
+ },
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ declare function func(arg: T): T;
+
+ export const value = {
+ func,
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ enum Fruit {
+ Apple,
+ Banana,
+ Cherry,
+ }
+
+ declare function func(arg: T): T;
+
+ export const value = {
+ func,
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Fruit',
+ },
+ endColumn: 19,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ enum Fruit {
+ Apple,
+ Banana,
+ Cherry,
+ }
+
+ declare const a: Fruit.Apple;
+
+ export const value = {
+ a,
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Fruit',
+ },
+ endColumn: 19,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ enum Fruit {
+ Apple,
+ Banana,
+ Cherry,
+ }
+
+ declare const a: Fruit.Apple;
+
+ export const value = {
+ key: () => a,
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Fruit',
+ },
+ endColumn: 19,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ enum Fruit {
+ Apple,
+ Banana,
+ Cherry,
+ }
+
+ declare const a: Fruit.Apple;
+
+ export const value = {
+ key: function () {
+ return a;
+ },
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Fruit',
+ },
+ endColumn: 19,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Item = {
+ key: string;
+ value: number;
+ };
+
+ type ItemKey = Item['key'];
+
+ const item: Item = { key: 'apple', value: 1 };
+
+ const map = new Map([['apple', item]]);
+
+ export const value = {
+ map,
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: { name: 'Item' },
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: { name: 'ItemKey' },
+ line: 7,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ const item: A = 1;
+
+ export const value = {
+ key: (() => item)(),
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ const item: A = 1;
+
+ export const value = {
+ key: ((a: A) => a)(item),
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ const item: A = 1;
+
+ export const value = {
+ key: ((a: T) => a)(item),
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ const item: A = 1;
+
+ export const value = {
+ key: ((a: A) => [a])(item),
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ const item: A = 1;
+
+ export const value = {
+ key: ((a: A) => ({ a }))(item),
+ };
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ export function func1(arg: R): R {
+ return func2(arg);
+ }
+
+ declare function func2(arg: T): T;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = string;
+
+ export function func1(arg: R): R {
+ doWork(String(arg));
+
+ return arg;
+ }
+
+ declare function doWork(arg: B): void;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = number;
+
+ export function func1(arg: R) {
+ return func2(arg);
+ }
+
+ declare function func2(arg: B): B;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = number;
+ type C = number;
+
+ export function func1(arg: R) {
+ if (Math.random() > 0.5) {
+ return func2(arg);
+ } else {
+ return func3(arg);
+ }
+ }
+
+ declare function func2(arg: B): B;
+ declare function func3(arg: C): C;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'C',
+ },
+ endColumn: 15,
+ line: 4,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = number;
+ type C = number;
+
+ export function func1(arg: R) {
+ switch (Math.random()) {
+ case 0:
+ return func2(arg);
+ case 1:
+ return func3(arg);
+ }
+ }
+
+ declare function func2(arg: B): B;
+ declare function func3(arg: C): C;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'C',
+ },
+ endColumn: 15,
+ line: 4,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = number;
+
+ export function func1(arg: R) {
+ const a = (() => {
+ return func2(arg);
+ })();
+
+ return arg;
+ }
+
+ declare function func2(arg: B): B;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = number;
+
+ export function func1(arg: R) {
+ return arg as B;
+ }
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = string;
+
+ export function func1(arg: R): R {
+ function doWork(arg2: B): void {}
+
+ doWork(String(arg));
+
+ return arg;
+ }
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type ItemsMap = Record;
+ type Key = keyof ItemsMap;
+
+ export function get(key: K): ItemsMap[K] {
+ return key as never;
+ }
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'ItemsMap',
+ },
+ endColumn: 22,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Key',
+ },
+ endColumn: 17,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ const value: A = 1;
+
+ export function func() {
+ return Math.random() > 0.5 && value;
+ }
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+ type B = string;
+
+ const valueA: A = 1;
+ const valueB: B = 'test';
+
+ export function func() {
+ return Math.random() > 0.5 ? valueA : valueB;
+ }
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'B',
+ },
+ endColumn: 15,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ declare function func(): string;
+
+ type A = string;
+
+ export default func();
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 4,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type Apple = 'apple';
+ type Banana = 'banana';
+
+ export type Fruits = Apple | Banana;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'Apple',
+ },
+ endColumn: 19,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 14,
+ data: {
+ name: 'Banana',
+ },
+ endColumn: 20,
+ line: 3,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ export interface B {
+ a: A;
+ }
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = number;
+
+ interface B {
+ b: string;
+ }
+
+ export namespace C {
+ export type D = A;
+ export type E = B;
+ }
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ {
+ column: 19,
+ data: {
+ name: 'B',
+ },
+ endColumn: 20,
+ line: 4,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ type A = 'test';
+ export type B = \`test-\${A}\`;
+ `,
+ errors: [
+ {
+ column: 14,
+ data: {
+ name: 'A',
+ },
+ endColumn: 15,
+ line: 2,
+ messageId: 'requireTypeExport',
+ },
+ ],
+ },
+ {
+ code: `
+ const fruits = { apple: 'apple' };
+
+ export function getFruit(
+ key: Key,
+ ): (typeof fruits)[Key] {
+ return fruits[key];
+ }
+ `,
+ errors: [
+ {
+ column: 15,
+ data: {
+ name: 'fruits',
+ },
+ endColumn: 21,
+ line: 2,
+ messageId: 'requireTypeQueryExport',
+ },
+ ],
+ },
+ {
+ code: `
+ const fruits = { apple: 'apple' };
+
+ export declare function processFruit(
+ fruit: F,
+ ): void;
+ `,
+ errors: [
+ {
+ column: 15,
+ data: {
+ name: 'fruits',
+ },
+ endColumn: 21,
+ line: 2,
+ messageId: 'requireTypeQueryExport',
+ },
+ ],
+ },
+ {
+ code: `
+ const fruits = { apple: 'apple' };
+
+ export declare function processFruit<
+ F extends Record,
+ >(fruit: F): void;
+ `,
+ errors: [
+ {
+ column: 15,
+ data: {
+ name: 'fruits',
+ },
+ endColumn: 21,
+ line: 2,
+ messageId: 'requireTypeQueryExport',
+ },
+ ],
+ },
+ ],
+});
diff --git a/packages/eslint-plugin/tests/schema-snapshots/require-types-exports.shot b/packages/eslint-plugin/tests/schema-snapshots/require-types-exports.shot
new file mode 100644
index 000000000000..2f0fbf6d8dfc
--- /dev/null
+++ b/packages/eslint-plugin/tests/schema-snapshots/require-types-exports.shot
@@ -0,0 +1,14 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Rule schemas should be convertible to TS types for documentation purposes require-types-exports 1`] = `
+"
+# SCHEMA:
+
+[]
+
+
+# TYPES:
+
+/** No options declared */
+type Options = [];"
+`;
diff --git a/packages/rule-tester/src/types/index.ts b/packages/rule-tester/src/types/index.ts
index becf16d2c5c9..a484d24f5000 100644
--- a/packages/rule-tester/src/types/index.ts
+++ b/packages/rule-tester/src/types/index.ts
@@ -2,7 +2,7 @@ import type { InvalidTestCase } from './InvalidTestCase';
import type { RuleTesterConfig } from './RuleTesterConfig';
import type { ValidTestCase } from './ValidTestCase';
-type Mutable = {
+export type Mutable = {
-readonly [P in keyof T]: T[P];
};
export type TesterConfigWithDefaults = Mutable<
diff --git a/packages/rule-tester/src/utils/SourceCodeFixer.ts b/packages/rule-tester/src/utils/SourceCodeFixer.ts
index 6a108c2e21ec..accb15767a4b 100644
--- a/packages/rule-tester/src/utils/SourceCodeFixer.ts
+++ b/packages/rule-tester/src/utils/SourceCodeFixer.ts
@@ -4,7 +4,7 @@ import type { Linter } from '@typescript-eslint/utils/ts-eslint';
import { hasOwnProperty } from './hasOwnProperty';
-type LintMessage = Linter.LintMessage | Linter.LintSuggestion;
+export type LintMessage = Linter.LintMessage | Linter.LintSuggestion;
type LintMessageWithFix = LintMessage & Required>;
const BOM = '\uFEFF';
diff --git a/packages/rule-tester/src/utils/config-validator.ts b/packages/rule-tester/src/utils/config-validator.ts
index bc5e09e7646c..50f73522b3d0 100644
--- a/packages/rule-tester/src/utils/config-validator.ts
+++ b/packages/rule-tester/src/utils/config-validator.ts
@@ -18,7 +18,7 @@ import { flatConfigSchema } from './flat-config-schema';
import { getRuleOptionsSchema } from './getRuleOptionsSchema';
import { hasOwnProperty } from './hasOwnProperty';
-type GetAdditionalRule = (ruleId: string) => AnyRuleModule | null;
+export type GetAdditionalRule = (ruleId: string) => AnyRuleModule | null;
const ajv = ajvBuilder();
const ruleValidators = new WeakMap();
diff --git a/packages/rule-tester/src/utils/deprecation-warnings.ts b/packages/rule-tester/src/utils/deprecation-warnings.ts
index 2453be707f45..230e7a4aed83 100644
--- a/packages/rule-tester/src/utils/deprecation-warnings.ts
+++ b/packages/rule-tester/src/utils/deprecation-warnings.ts
@@ -3,7 +3,7 @@
import path from 'node:path';
// Definitions for deprecation warnings.
-const deprecationWarningMessages = {
+export const deprecationWarningMessages = {
ESLINT_LEGACY_ECMAFEATURES:
"The 'ecmaFeatures' config file property is deprecated and has no effect.",
} as const;
diff --git a/packages/rule-tester/src/utils/flat-config-schema.ts b/packages/rule-tester/src/utils/flat-config-schema.ts
index 1b631070a3e0..cacd9eb35381 100644
--- a/packages/rule-tester/src/utils/flat-config-schema.ts
+++ b/packages/rule-tester/src/utils/flat-config-schema.ts
@@ -7,9 +7,9 @@ import type {
import { normalizeSeverityToNumber } from './severity';
-type PluginMemberName = `${string}/${string}`;
+export type PluginMemberName = `${string}/${string}`;
-interface ObjectPropertySchema {
+export interface ObjectPropertySchema {
merge: string | ((a: T, b: T) => T);
validate: string | ((value: unknown) => asserts value is T);
}
@@ -423,7 +423,7 @@ const processorSchema: ObjectPropertySchema = {
},
};
-type ConfigRules = Record;
+export type ConfigRules = Record;
const rulesSchema = {
merge(first: ConfigRules = {}, second: ConfigRules = {}): ConfigRules {
diff --git a/packages/typescript-eslint/src/configs/all.ts b/packages/typescript-eslint/src/configs/all.ts
index cd16389445a5..075bee1840e8 100644
--- a/packages/typescript-eslint/src/configs/all.ts
+++ b/packages/typescript-eslint/src/configs/all.ts
@@ -161,6 +161,7 @@ export default (
'@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',
diff --git a/packages/typescript-eslint/src/configs/disable-type-checked.ts b/packages/typescript-eslint/src/configs/disable-type-checked.ts
index eeb80399882c..8ab7a8df71f6 100644
--- a/packages/typescript-eslint/src/configs/disable-type-checked.ts
+++ b/packages/typescript-eslint/src/configs/disable-type-checked.ts
@@ -76,6 +76,6 @@ export default (
'@typescript-eslint/use-unknown-in-catch-callback-variable': 'off',
},
languageOptions: {
- parserOptions: { project: false, program: null, projectService: false },
+ parserOptions: { program: null, project: false, projectService: false },
},
});
diff --git a/packages/typescript-eslint/src/configs/strict-type-checked-only.ts b/packages/typescript-eslint/src/configs/strict-type-checked-only.ts
index c9efc88da6c3..ef29e1006bc4 100644
--- a/packages/typescript-eslint/src/configs/strict-type-checked-only.ts
+++ b/packages/typescript-eslint/src/configs/strict-type-checked-only.ts
@@ -74,10 +74,10 @@ export default (
{
allowAny: false,
allowBoolean: false,
+ allowNever: false,
allowNullish: false,
allowNumber: false,
allowRegExp: false,
- allowNever: false,
},
],
'no-return-await': 'off',
diff --git a/packages/typescript-eslint/src/configs/strict-type-checked.ts b/packages/typescript-eslint/src/configs/strict-type-checked.ts
index 4f354baf7e40..e9481d6050a6 100644
--- a/packages/typescript-eslint/src/configs/strict-type-checked.ts
+++ b/packages/typescript-eslint/src/configs/strict-type-checked.ts
@@ -92,6 +92,7 @@ export default (
'@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',
{
@@ -107,10 +108,10 @@ export default (
{
allowAny: false,
allowBoolean: false,
+ allowNever: false,
allowNullish: false,
allowNumber: false,
allowRegExp: false,
- allowNever: false,
},
],
'no-return-await': 'off',
diff --git a/packages/typescript-eslint/src/configs/strict.ts b/packages/typescript-eslint/src/configs/strict.ts
index 0afa85b9f088..ab3f8aa2388e 100644
--- a/packages/typescript-eslint/src/configs/strict.ts
+++ b/packages/typescript-eslint/src/configs/strict.ts
@@ -56,6 +56,7 @@ export default (
'@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',
},
diff --git a/packages/typescript-estree/src/node-utils.ts b/packages/typescript-estree/src/node-utils.ts
index 943ee4c95079..9793f4762773 100644
--- a/packages/typescript-estree/src/node-utils.ts
+++ b/packages/typescript-estree/src/node-utils.ts
@@ -11,7 +11,7 @@ const isAtLeast50 = typescriptVersionIsAtLeast['5.0'];
const SyntaxKind = ts.SyntaxKind;
-type LogicalOperatorKind =
+export type LogicalOperatorKind =
| ts.SyntaxKind.AmpersandAmpersandToken
| ts.SyntaxKind.BarBarToken
| ts.SyntaxKind.QuestionQuestionToken;
@@ -31,7 +31,7 @@ interface TokenToText
[SyntaxKind.UniqueKeyword]: 'unique';
}
-type AssignmentOperatorKind = keyof TSESTree.AssignmentOperatorToText;
+export type AssignmentOperatorKind = keyof TSESTree.AssignmentOperatorToText;
const ASSIGNMENT_OPERATORS: ReadonlySet = new Set([
ts.SyntaxKind.AmpersandAmpersandEqualsToken,
ts.SyntaxKind.AmpersandEqualsToken,
@@ -51,7 +51,7 @@ const ASSIGNMENT_OPERATORS: ReadonlySet = new Set([
ts.SyntaxKind.SlashEqualsToken,
]);
-type BinaryOperatorKind = keyof TSESTree.BinaryOperatorToText;
+export type BinaryOperatorKind = keyof TSESTree.BinaryOperatorToText;
const BINARY_OPERATORS: ReadonlySet = new Set([
SyntaxKind.AmpersandAmpersandToken,
SyntaxKind.AmpersandToken,
@@ -79,7 +79,7 @@ const BINARY_OPERATORS: ReadonlySet = new Set([
SyntaxKind.SlashToken,
]);
-type DeclarationKind = TSESTree.VariableDeclaration['kind'];
+export type DeclarationKind = TSESTree.VariableDeclaration['kind'];
/**
* Returns true if the given ts.Token is the assignment operator
@@ -107,9 +107,8 @@ export function isESTreeBinaryOperator(
return (BINARY_OPERATORS as ReadonlySet).has(operator.kind);
}
-type TokenForTokenKind = T extends keyof TokenToText
- ? TokenToText[T]
- : string | undefined;
+export type TokenForTokenKind =
+ T extends keyof TokenToText ? TokenToText[T] : string | undefined;
/**
* Returns the string form of the given TSToken SyntaxKind
*/
diff --git a/packages/typescript-estree/src/parseSettings/index.ts b/packages/typescript-estree/src/parseSettings/index.ts
index 1ea208210e0a..6f2039de080d 100644
--- a/packages/typescript-estree/src/parseSettings/index.ts
+++ b/packages/typescript-estree/src/parseSettings/index.ts
@@ -5,7 +5,7 @@ import type { CanonicalPath } from '../create-program/shared';
import type { TSESTree } from '../ts-estree';
import type { CacheLike } from './ExpiringCache';
-type DebugModule = 'eslint' | 'typescript' | 'typescript-eslint';
+export type DebugModule = 'eslint' | 'typescript' | 'typescript-eslint';
// Workaround to support new TS version features for consumers on old TS versions
declare module 'typescript' {
diff --git a/packages/typescript-estree/src/parser-options.ts b/packages/typescript-estree/src/parser-options.ts
index 48cbf0b8da1c..77a8e29b28e3 100644
--- a/packages/typescript-estree/src/parser-options.ts
+++ b/packages/typescript-estree/src/parser-options.ts
@@ -111,7 +111,7 @@ interface ParseOptions {
suppressDeprecatedPropertyWarnings?: boolean;
}
-interface ParseAndGenerateServicesOptions extends ParseOptions {
+export interface ParseAndGenerateServicesOptions extends ParseOptions {
/**
* Granular control of the expiry lifetime of our internal caches.
* You can specify the number of seconds as an integer number, or the string
diff --git a/packages/typescript-estree/src/simple-traverse.ts b/packages/typescript-estree/src/simple-traverse.ts
index aa0d7ed4d070..fc64de4ec040 100644
--- a/packages/typescript-estree/src/simple-traverse.ts
+++ b/packages/typescript-estree/src/simple-traverse.ts
@@ -21,7 +21,7 @@ function getVisitorKeysForNode(
return (keys ?? []) as never;
}
-type SimpleTraverseOptions = Readonly<
+export type SimpleTraverseOptions = Readonly<
| {
enter: (node: TSESTree.Node, parent: TSESTree.Node | undefined) => void;
visitorKeys?: Readonly;
diff --git a/packages/typescript-estree/tests/test-utils/test-utils.ts b/packages/typescript-estree/tests/test-utils/test-utils.ts
index 3ea4e57ea175..35daef3f6f1f 100644
--- a/packages/typescript-estree/tests/test-utils/test-utils.ts
+++ b/packages/typescript-estree/tests/test-utils/test-utils.ts
@@ -82,7 +82,7 @@ export function deeplyCopy>(ast: T): T {
return omitDeep(ast) as T;
}
-type UnknownObject = Record;
+export type UnknownObject = Record;
function isObjectLike(value: unknown): boolean {
return (
diff --git a/packages/utils/src/ast-utils/eslint-utils/ReferenceTracker.ts b/packages/utils/src/ast-utils/eslint-utils/ReferenceTracker.ts
index e18a01e21f1a..cdab1852d20d 100644
--- a/packages/utils/src/ast-utils/eslint-utils/ReferenceTracker.ts
+++ b/packages/utils/src/ast-utils/eslint-utils/ReferenceTracker.ts
@@ -41,7 +41,7 @@ interface ReferenceTracker {
traceMap: ReferenceTracker.TraceMap,
): IterableIterator>;
}
-interface ReferenceTrackerStatic {
+export interface ReferenceTrackerStatic {
readonly CALL: typeof ReferenceTrackerCALL;
readonly CONSTRUCT: typeof ReferenceTrackerCONSTRUCT;
readonly ESM: typeof ReferenceTrackerESM;
diff --git a/packages/utils/src/ts-eslint/Rule.ts b/packages/utils/src/ts-eslint/Rule.ts
index 3b281090606b..abbfc0f87a5f 100644
--- a/packages/utils/src/ts-eslint/Rule.ts
+++ b/packages/utils/src/ts-eslint/Rule.ts
@@ -154,7 +154,7 @@ interface ReportDescriptorBase {
// we disallow this because it's much better to use messageIds for reusable errors that are easily testable
// readonly desc?: string;
}
-interface ReportDescriptorWithSuggestion
+export interface ReportDescriptorWithSuggestion
extends ReportDescriptorBase {
/**
* 6.7's Suggestions API
@@ -162,7 +162,7 @@ interface ReportDescriptorWithSuggestion
readonly suggest?: Readonly> | null;
}
-interface ReportDescriptorNodeOptionalLoc {
+export interface ReportDescriptorNodeOptionalLoc {
/**
* An override of the location of the report
*/
@@ -174,7 +174,7 @@ interface ReportDescriptorNodeOptionalLoc {
*/
readonly node: TSESTree.Node | TSESTree.Token;
}
-interface ReportDescriptorLocOnly {
+export interface ReportDescriptorLocOnly {
/**
* An override of the location of the report
*/
@@ -425,7 +425,7 @@ export type RuleFunction = (
node: T,
) => void;
-interface RuleListenerBaseSelectors {
+export interface RuleListenerBaseSelectors {
AccessorProperty?: RuleFunction;
ArrayExpression?: RuleFunction;
ArrayPattern?: RuleFunction;
@@ -595,10 +595,13 @@ interface RuleListenerBaseSelectors {
WithStatement?: RuleFunction;
YieldExpression?: RuleFunction;
}
-type RuleListenerExitSelectors = {
+export type RuleListenerExitSelectors = {
[K in keyof RuleListenerBaseSelectors as `${K}:exit`]: RuleListenerBaseSelectors[K];
};
-type RuleListenerCatchAllBaseCase = Record;
+export type RuleListenerCatchAllBaseCase = Record<
+ string,
+ RuleFunction | undefined
+>;
// Interface to merge into for anyone that wants to add more selectors
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface RuleListenerExtension {
diff --git a/packages/website/src/components/FinancialContributors/Sponsor.tsx b/packages/website/src/components/FinancialContributors/Sponsor.tsx
index 3f3ce6d8036f..614d8be95f95 100644
--- a/packages/website/src/components/FinancialContributors/Sponsor.tsx
+++ b/packages/website/src/components/FinancialContributors/Sponsor.tsx
@@ -5,7 +5,7 @@ import type { SponsorData } from './types';
import styles from './styles.module.css';
-interface SponsorProps {
+export interface SponsorProps {
includeName?: boolean;
sponsor: SponsorData;
}
diff --git a/packages/website/src/components/FinancialContributors/Sponsors/index.tsx b/packages/website/src/components/FinancialContributors/Sponsors/index.tsx
index 68fc7cac4bfe..c0967820006f 100644
--- a/packages/website/src/components/FinancialContributors/Sponsors/index.tsx
+++ b/packages/website/src/components/FinancialContributors/Sponsors/index.tsx
@@ -6,7 +6,7 @@ import type { SponsorData } from '../types';
import { Sponsor } from '../Sponsor';
import styles from './styles.module.css';
-interface SponsorsProps {
+export interface SponsorsProps {
className: string;
expanded?: boolean;
includeName?: boolean;
diff --git a/packages/website/src/components/ast/tsUtils.ts b/packages/website/src/components/ast/tsUtils.ts
index bc00c84c3306..7d002da97f4f 100644
--- a/packages/website/src/components/ast/tsUtils.ts
+++ b/packages/website/src/components/ast/tsUtils.ts
@@ -1,4 +1,4 @@
-interface TsParsedEnums {
+export interface TsParsedEnums {
LanguageVariant: Record;
ModifierFlags: Record;
NodeFlags: Record;
diff --git a/packages/website/src/components/config/ConfigTypeScript.tsx b/packages/website/src/components/config/ConfigTypeScript.tsx
index 16400a0aa2dd..8215b859ef45 100644
--- a/packages/website/src/components/config/ConfigTypeScript.tsx
+++ b/packages/website/src/components/config/ConfigTypeScript.tsx
@@ -8,7 +8,7 @@ import { getTypescriptOptions } from '../lib/jsonSchema';
import { shallowEqual } from '../lib/shallowEqual';
import ConfigEditor from './ConfigEditor';
-interface ConfigTypeScriptProps {
+export interface ConfigTypeScriptProps {
readonly className?: string;
readonly config?: string;
readonly onChange: (config: Partial) => void;
diff --git a/packages/website/src/components/editor/loadSandbox.ts b/packages/website/src/components/editor/loadSandbox.ts
index 1521e7cf5aa3..1aab845828a4 100644
--- a/packages/website/src/components/editor/loadSandbox.ts
+++ b/packages/website/src/components/editor/loadSandbox.ts
@@ -3,8 +3,8 @@ import type MonacoEditor from 'monaco-editor';
import type * as SandboxFactory from '../../vendor/sandbox';
import type { WebLinterModule } from '../linter/types';
-type Monaco = typeof MonacoEditor;
-type Sandbox = typeof SandboxFactory;
+export type Monaco = typeof MonacoEditor;
+export type Sandbox = typeof SandboxFactory;
export interface SandboxModel {
lintUtils: WebLinterModule;
diff --git a/packages/website/src/components/linter/bridge.ts b/packages/website/src/components/linter/bridge.ts
index 414873484c1a..c4d17174748f 100644
--- a/packages/website/src/components/linter/bridge.ts
+++ b/packages/website/src/components/linter/bridge.ts
@@ -7,9 +7,11 @@ import type { PlaygroundSystem } from './types';
import { debounce } from '../lib/debounce';
import { getPathRegExp } from './utils';
+export type TSVFS = typeof tsvfs;
+
export function createFileSystem(
config: Pick,
- vfs: typeof tsvfs,
+ vfs: TSVFS,
): PlaygroundSystem {
const files = new Map();
files.set(`/.eslintrc`, config.eslintrc);
diff --git a/packages/website/src/components/linter/createLinter.ts b/packages/website/src/components/linter/createLinter.ts
index 78f001439d87..449b847f5344 100644
--- a/packages/website/src/components/linter/createLinter.ts
+++ b/packages/website/src/components/linter/createLinter.ts
@@ -38,10 +38,12 @@ export interface CreateLinter {
updateParserOptions(sourceType?: SourceType): void;
}
+export type TSVFS = typeof tsvfs;
+
export function createLinter(
system: PlaygroundSystem,
webLinterModule: WebLinterModule,
- vfs: typeof tsvfs,
+ vfs: TSVFS,
): CreateLinter {
const rules: CreateLinter['rules'] = new Map();
const configs = new Map(Object.entries(webLinterModule.configs));
diff --git a/packages/website/src/components/linter/createParser.ts b/packages/website/src/components/linter/createParser.ts
index 6af8e0af3b85..9e2cf874bd3e 100644
--- a/packages/website/src/components/linter/createParser.ts
+++ b/packages/website/src/components/linter/createParser.ts
@@ -12,12 +12,14 @@ import type {
import { defaultParseSettings } from './config';
+export type TSVFS = typeof tsvfs;
+
export function createParser(
system: PlaygroundSystem,
compilerOptions: ts.CompilerOptions,
onUpdate: (filename: string, model: UpdateModel) => void,
utils: WebLinterModule,
- vfs: typeof tsvfs,
+ vfs: TSVFS,
): {
updateConfig: (compilerOptions: ts.CompilerOptions) => void;
} & Parser.ParserModule {