diff --git a/packages/eslint-plugin/docs/rules/no-useless-default-assignment.mdx b/packages/eslint-plugin/docs/rules/no-useless-default-assignment.mdx
new file mode 100644
index 000000000000..258e9b5b812b
--- /dev/null
+++ b/packages/eslint-plugin/docs/rules/no-useless-default-assignment.mdx
@@ -0,0 +1,53 @@
+---
+description: 'Disallow default values that will never be used.'
+---
+
+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/no-useless-default-assignment** for documentation.
+
+[Default parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) and [default values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#default_value) are only used if the parameter or property is `undefined`.
+That can happen when a value is missing, or when one is provided and set to `undefined`.
+If a non-`undefined` value is guaranteed to be provided, then there is no need to define a default.
+
+## Examples
+
+
+
+
+```ts
+function Bar({ foo = '' }: { foo: string }) {
+ return foo;
+}
+
+const { foo = '' } = { foo: 'bar' };
+
+const [foo = ''] = ['bar'];
+
+[1, 2, 3].map((a = 42) => a + 1);
+```
+
+
+
+
+```ts
+function Bar({ foo = '' }: { foo?: string }) {
+ return foo;
+}
+
+const { foo = '' } = { foo: undefined };
+
+const [foo = ''] = [undefined];
+
+[1, 2, 3, undefined].map((a = 42) => a + 1);
+```
+
+
+
+
+## When Not To Use It
+
+If you use default values defensively against runtime values that bypass type checking, or for documentation purposes, you may want to disable this rule.
diff --git a/packages/eslint-plugin/src/configs/eslintrc/all.ts b/packages/eslint-plugin/src/configs/eslintrc/all.ts
index 78c8420e2643..11221a74807b 100644
--- a/packages/eslint-plugin/src/configs/eslintrc/all.ts
+++ b/packages/eslint-plugin/src/configs/eslintrc/all.ts
@@ -120,6 +120,7 @@ export = {
'@typescript-eslint/no-use-before-define': 'error',
'no-useless-constructor': 'off',
'@typescript-eslint/no-useless-constructor': 'error',
+ '@typescript-eslint/no-useless-default-assignment': 'error',
'@typescript-eslint/no-useless-empty-export': 'error',
'@typescript-eslint/no-wrapper-object-types': 'error',
'@typescript-eslint/non-nullable-type-assertion-style': 'error',
diff --git a/packages/eslint-plugin/src/configs/eslintrc/disable-type-checked.ts b/packages/eslint-plugin/src/configs/eslintrc/disable-type-checked.ts
index 6853a151722d..277f99228c1d 100644
--- a/packages/eslint-plugin/src/configs/eslintrc/disable-type-checked.ts
+++ b/packages/eslint-plugin/src/configs/eslintrc/disable-type-checked.ts
@@ -44,6 +44,7 @@ export = {
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-unsafe-type-assertion': 'off',
'@typescript-eslint/no-unsafe-unary-minus': 'off',
+ '@typescript-eslint/no-useless-default-assignment': 'off',
'@typescript-eslint/non-nullable-type-assertion-style': 'off',
'@typescript-eslint/only-throw-error': 'off',
'@typescript-eslint/prefer-destructuring': 'off',
diff --git a/packages/eslint-plugin/src/configs/eslintrc/strict-type-checked-only.ts b/packages/eslint-plugin/src/configs/eslintrc/strict-type-checked-only.ts
index a2b5b457d01e..c455ac88371b 100644
--- a/packages/eslint-plugin/src/configs/eslintrc/strict-type-checked-only.ts
+++ b/packages/eslint-plugin/src/configs/eslintrc/strict-type-checked-only.ts
@@ -39,6 +39,7 @@ export = {
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
'@typescript-eslint/no-unsafe-unary-minus': 'error',
+ '@typescript-eslint/no-useless-default-assignment': 'error',
'no-throw-literal': 'off',
'@typescript-eslint/only-throw-error': 'error',
'prefer-promise-reject-errors': 'off',
diff --git a/packages/eslint-plugin/src/configs/eslintrc/strict-type-checked.ts b/packages/eslint-plugin/src/configs/eslintrc/strict-type-checked.ts
index ec1523d8b48e..aba8c3006a1a 100644
--- a/packages/eslint-plugin/src/configs/eslintrc/strict-type-checked.ts
+++ b/packages/eslint-plugin/src/configs/eslintrc/strict-type-checked.ts
@@ -68,6 +68,7 @@ export = {
'@typescript-eslint/no-unused-vars': 'error',
'no-useless-constructor': 'off',
'@typescript-eslint/no-useless-constructor': 'error',
+ '@typescript-eslint/no-useless-default-assignment': 'error',
'@typescript-eslint/no-wrapper-object-types': 'error',
'no-throw-literal': 'off',
'@typescript-eslint/only-throw-error': 'error',
diff --git a/packages/eslint-plugin/src/configs/flat/all.ts b/packages/eslint-plugin/src/configs/flat/all.ts
index 43792419ab3b..7e61ed948ab9 100644
--- a/packages/eslint-plugin/src/configs/flat/all.ts
+++ b/packages/eslint-plugin/src/configs/flat/all.ts
@@ -134,6 +134,7 @@ export default (
'@typescript-eslint/no-use-before-define': 'error',
'no-useless-constructor': 'off',
'@typescript-eslint/no-useless-constructor': 'error',
+ '@typescript-eslint/no-useless-default-assignment': 'error',
'@typescript-eslint/no-useless-empty-export': 'error',
'@typescript-eslint/no-wrapper-object-types': 'error',
'@typescript-eslint/non-nullable-type-assertion-style': 'error',
diff --git a/packages/eslint-plugin/src/configs/flat/disable-type-checked.ts b/packages/eslint-plugin/src/configs/flat/disable-type-checked.ts
index 5a48e1722775..7603dde91c7a 100644
--- a/packages/eslint-plugin/src/configs/flat/disable-type-checked.ts
+++ b/packages/eslint-plugin/src/configs/flat/disable-type-checked.ts
@@ -51,6 +51,7 @@ export default (
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-unsafe-type-assertion': 'off',
'@typescript-eslint/no-unsafe-unary-minus': 'off',
+ '@typescript-eslint/no-useless-default-assignment': 'off',
'@typescript-eslint/non-nullable-type-assertion-style': 'off',
'@typescript-eslint/only-throw-error': 'off',
'@typescript-eslint/prefer-destructuring': 'off',
diff --git a/packages/eslint-plugin/src/configs/flat/strict-type-checked-only.ts b/packages/eslint-plugin/src/configs/flat/strict-type-checked-only.ts
index 043f1aad0cd5..2cddf49a4633 100644
--- a/packages/eslint-plugin/src/configs/flat/strict-type-checked-only.ts
+++ b/packages/eslint-plugin/src/configs/flat/strict-type-checked-only.ts
@@ -52,6 +52,7 @@ export default (
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
'@typescript-eslint/no-unsafe-unary-minus': 'error',
+ '@typescript-eslint/no-useless-default-assignment': 'error',
'no-throw-literal': 'off',
'@typescript-eslint/only-throw-error': 'error',
'prefer-promise-reject-errors': 'off',
diff --git a/packages/eslint-plugin/src/configs/flat/strict-type-checked.ts b/packages/eslint-plugin/src/configs/flat/strict-type-checked.ts
index b3c0a2391178..4d34eb4925d8 100644
--- a/packages/eslint-plugin/src/configs/flat/strict-type-checked.ts
+++ b/packages/eslint-plugin/src/configs/flat/strict-type-checked.ts
@@ -81,6 +81,7 @@ export default (
'@typescript-eslint/no-unused-vars': 'error',
'no-useless-constructor': 'off',
'@typescript-eslint/no-useless-constructor': 'error',
+ '@typescript-eslint/no-useless-default-assignment': 'error',
'@typescript-eslint/no-wrapper-object-types': 'error',
'no-throw-literal': 'off',
'@typescript-eslint/only-throw-error': 'error',
diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts
index 9ee5903aa5f7..c32c32967519 100644
--- a/packages/eslint-plugin/src/rules/index.ts
+++ b/packages/eslint-plugin/src/rules/index.ts
@@ -92,6 +92,7 @@ import noUnusedPrivateClassMembers from './no-unused-private-class-members';
import noUnusedVars from './no-unused-vars';
import noUseBeforeDefine from './no-use-before-define';
import noUselessConstructor from './no-useless-constructor';
+import noUselessDefaultAssignment from './no-useless-default-assignment';
import noUselessEmptyExport from './no-useless-empty-export';
import noVarRequires from './no-var-requires';
import noWrapperObjectTypes from './no-wrapper-object-types';
@@ -227,6 +228,7 @@ const rules = {
'no-unused-vars': noUnusedVars,
'no-use-before-define': noUseBeforeDefine,
'no-useless-constructor': noUselessConstructor,
+ 'no-useless-default-assignment': noUselessDefaultAssignment,
'no-useless-empty-export': noUselessEmptyExport,
'no-var-requires': noVarRequires,
'no-wrapper-object-types': noWrapperObjectTypes,
diff --git a/packages/eslint-plugin/src/rules/no-useless-default-assignment.ts b/packages/eslint-plugin/src/rules/no-useless-default-assignment.ts
new file mode 100644
index 000000000000..f33631df44a4
--- /dev/null
+++ b/packages/eslint-plugin/src/rules/no-useless-default-assignment.ts
@@ -0,0 +1,263 @@
+import type { TSESTree } from '@typescript-eslint/utils';
+
+import { AST_NODE_TYPES } from '@typescript-eslint/utils';
+import * as tsutils from 'ts-api-utils';
+import * as ts from 'typescript';
+
+import {
+ createRule,
+ getParserServices,
+ isFunction,
+ isTypeAnyType,
+ isTypeFlagSet,
+ isTypeUnknownType,
+ nullThrows,
+ NullThrowsReasons,
+} from '../util';
+
+type MessageId = 'uselessDefaultAssignment' | 'uselessUndefined';
+
+export default createRule<[], MessageId>({
+ name: 'no-useless-default-assignment',
+ meta: {
+ type: 'suggestion',
+ docs: {
+ description: 'Disallow default values that will never be used',
+ recommended: 'strict',
+ requiresTypeChecking: true,
+ },
+ fixable: 'code',
+ messages: {
+ uselessDefaultAssignment:
+ 'Default value is useless because the {{ type }} is not optional.',
+ uselessUndefined:
+ 'Default value is useless because it is undefined. Optional {{ type }}s are already undefined by default.',
+ },
+ schema: [],
+ },
+ defaultOptions: [],
+ create(context) {
+ const services = getParserServices(context);
+ const checker = services.program.getTypeChecker();
+ const compilerOptions = services.program.getCompilerOptions();
+ const isNoUncheckedIndexedAccess = tsutils.isCompilerOptionEnabled(
+ compilerOptions,
+ 'noUncheckedIndexedAccess',
+ );
+
+ function canBeUndefined(type: ts.Type): boolean {
+ if (isTypeAnyType(type) || isTypeUnknownType(type)) {
+ return true;
+ }
+ return tsutils
+ .unionConstituents(type)
+ .some(part => isTypeFlagSet(part, ts.TypeFlags.Undefined));
+ }
+
+ function getPropertyType(
+ objectType: ts.Type,
+ propertyName: string,
+ ): ts.Type | null {
+ const symbol = objectType.getProperty(propertyName);
+ if (!symbol) {
+ if (isNoUncheckedIndexedAccess) {
+ return null;
+ }
+ return objectType.getStringIndexType() ?? null;
+ }
+ return checker.getTypeOfSymbol(symbol);
+ }
+
+ function getArrayElementType(
+ arrayType: ts.Type,
+ elementIndex: number,
+ ): ts.Type | null {
+ if (checker.isTupleType(arrayType)) {
+ const tupleArgs = checker.getTypeArguments(arrayType);
+ if (elementIndex < tupleArgs.length) {
+ return tupleArgs[elementIndex];
+ }
+ }
+
+ if (isNoUncheckedIndexedAccess) {
+ return null;
+ }
+
+ return arrayType.getNumberIndexType() ?? null;
+ }
+
+ function checkAssignmentPattern(node: TSESTree.AssignmentPattern): void {
+ if (
+ node.right.type === AST_NODE_TYPES.Identifier &&
+ node.right.name === 'undefined'
+ ) {
+ const type =
+ node.parent.type === AST_NODE_TYPES.Property ||
+ node.parent.type === AST_NODE_TYPES.ArrayPattern
+ ? 'property'
+ : 'parameter';
+ reportUselessDefault(node, type, 'uselessUndefined');
+ return;
+ }
+
+ const parent = node.parent;
+
+ if (
+ parent.type === AST_NODE_TYPES.ArrowFunctionExpression ||
+ parent.type === AST_NODE_TYPES.FunctionExpression
+ ) {
+ const paramIndex = parent.params.indexOf(node);
+ if (paramIndex !== -1) {
+ const tsFunc = services.esTreeNodeToTSNodeMap.get(parent);
+ if (ts.isFunctionLike(tsFunc)) {
+ const contextualType = checker.getContextualType(
+ tsFunc as ts.Expression,
+ );
+ if (!contextualType) {
+ return;
+ }
+
+ const signatures = contextualType.getCallSignatures();
+ const params = signatures[0].getParameters();
+ if (paramIndex < params.length) {
+ const paramSymbol = params[paramIndex];
+ if ((paramSymbol.flags & ts.SymbolFlags.Optional) === 0) {
+ const paramType = checker.getTypeOfSymbol(paramSymbol);
+ if (!canBeUndefined(paramType)) {
+ reportUselessDefault(
+ node,
+ 'parameter',
+ 'uselessDefaultAssignment',
+ );
+ }
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ if (parent.type === AST_NODE_TYPES.Property) {
+ const propertyType = getTypeOfProperty(parent);
+ if (!propertyType) {
+ return;
+ }
+
+ if (!canBeUndefined(propertyType)) {
+ reportUselessDefault(node, 'property', 'uselessDefaultAssignment');
+ }
+ } else if (parent.type === AST_NODE_TYPES.ArrayPattern) {
+ const sourceType = getSourceTypeForPattern(parent);
+ if (!sourceType) {
+ return;
+ }
+
+ const elementIndex = parent.elements.indexOf(node);
+ const elementType = getArrayElementType(sourceType, elementIndex);
+ if (!elementType) {
+ return;
+ }
+
+ if (!canBeUndefined(elementType)) {
+ reportUselessDefault(node, 'property', 'uselessDefaultAssignment');
+ }
+ }
+ }
+
+ function getTypeOfProperty(node: TSESTree.Property): ts.Type | null {
+ const objectPattern = node.parent as TSESTree.ObjectPattern;
+ const sourceType = getSourceTypeForPattern(objectPattern);
+ if (!sourceType) {
+ return null;
+ }
+
+ const propertyName = getPropertyName(node.key);
+ if (!propertyName) {
+ return null;
+ }
+
+ return getPropertyType(sourceType, propertyName);
+ }
+
+ function getSourceTypeForPattern(pattern: TSESTree.Node): ts.Type | null {
+ const parent = nullThrows(
+ pattern.parent,
+ NullThrowsReasons.MissingParent,
+ );
+
+ if (parent.type === AST_NODE_TYPES.VariableDeclarator && parent.init) {
+ const tsNode = services.esTreeNodeToTSNodeMap.get(parent.init);
+ return checker.getTypeAtLocation(tsNode);
+ }
+
+ if (isFunction(parent)) {
+ const paramIndex = parent.params.indexOf(pattern as TSESTree.Parameter);
+ const tsFunc = services.esTreeNodeToTSNodeMap.get(parent);
+ const signature = nullThrows(
+ checker.getSignatureFromDeclaration(tsFunc),
+ NullThrowsReasons.MissingToken('signature', 'function'),
+ );
+ const params = signature.getParameters();
+ return checker.getTypeOfSymbol(params[paramIndex]);
+ }
+
+ if (parent.type === AST_NODE_TYPES.AssignmentPattern) {
+ return getSourceTypeForPattern(parent);
+ }
+
+ if (parent.type === AST_NODE_TYPES.Property) {
+ return getTypeOfProperty(parent);
+ }
+
+ if (parent.type === AST_NODE_TYPES.ArrayPattern) {
+ const arrayPattern = parent;
+ const arrayType = getSourceTypeForPattern(arrayPattern);
+ if (!arrayType) {
+ return null;
+ }
+ const elementIndex = arrayPattern.elements.indexOf(
+ pattern as TSESTree.DestructuringPattern,
+ );
+ return getArrayElementType(arrayType, elementIndex);
+ }
+
+ return null;
+ }
+
+ function getPropertyName(
+ key: TSESTree.Expression | TSESTree.PrivateIdentifier,
+ ): string | null {
+ switch (key.type) {
+ case AST_NODE_TYPES.Identifier:
+ return key.name;
+ case AST_NODE_TYPES.Literal:
+ return String(key.value);
+ default:
+ return null;
+ }
+ }
+
+ function reportUselessDefault(
+ node: TSESTree.AssignmentPattern,
+ type: 'parameter' | 'property',
+ messageId: MessageId,
+ ): void {
+ context.report({
+ node: node.right,
+ messageId,
+ data: { type },
+ fix(fixer) {
+ // Remove from before the = to the end of the default value
+ // Find the start position (including whitespace before =)
+ const start = node.left.range[1];
+ const end = node.range[1];
+ return fixer.removeRange([start, end]);
+ },
+ });
+ }
+
+ return {
+ AssignmentPattern: checkAssignmentPattern,
+ };
+ },
+});
diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-useless-default-assignment.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-useless-default-assignment.shot
new file mode 100644
index 000000000000..b63ea9a740f0
--- /dev/null
+++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-useless-default-assignment.shot
@@ -0,0 +1,27 @@
+Incorrect
+
+function Bar({ foo = '' }: { foo: string }) {
+ ~~ Default value is useless because the property is not optional.
+ return foo;
+}
+
+const { foo = '' } = { foo: 'bar' };
+ ~~ Default value is useless because the property is not optional.
+
+const [foo = ''] = ['bar'];
+ ~~ Default value is useless because the property is not optional.
+
+[1, 2, 3].map((a = 42) => a + 1);
+ ~~ Default value is useless because the parameter is not optional.
+
+Correct
+
+function Bar({ foo = '' }: { foo?: string }) {
+ return foo;
+}
+
+const { foo = '' } = { foo: undefined };
+
+const [foo = ''] = [undefined];
+
+[1, 2, 3, undefined].map((a = 42) => a + 1);
diff --git a/packages/eslint-plugin/tests/rules/no-useless-default-assignment.test.ts b/packages/eslint-plugin/tests/rules/no-useless-default-assignment.test.ts
new file mode 100644
index 000000000000..d5d52b5bd0db
--- /dev/null
+++ b/packages/eslint-plugin/tests/rules/no-useless-default-assignment.test.ts
@@ -0,0 +1,520 @@
+import rule from '../../src/rules/no-useless-default-assignment';
+import { createRuleTesterWithTypes, getFixturesRootDir } from '../RuleTester';
+
+const rootDir = getFixturesRootDir();
+const ruleTester = createRuleTesterWithTypes();
+
+ruleTester.run('no-useless-default-assignment', rule, {
+ valid: [
+ `
+ function Bar({ foo = '' }: { foo?: string }) {
+ return foo;
+ }
+ `,
+ `
+ const { foo } = { foo: 'bar' };
+ `,
+ `
+ [1, 2, 3, undefined].map((a = 42) => a + 1);
+ `,
+ `
+ function test(a?: number) {
+ return a;
+ }
+ `,
+ `
+ const obj: { a?: string } = {};
+ const { a = 'default' } = obj;
+ `,
+ `
+ function test(a: string | undefined = 'default') {
+ return a;
+ }
+ `,
+ `
+ (a: string = 'default') => a;
+ `,
+ `
+ function test(a: string = 'default') {
+ return a;
+ }
+ `,
+ `
+ class C {
+ public test(a: string = 'default') {
+ return a;
+ }
+ }
+ `,
+ `
+ const obj: { a: string | undefined } = { a: undefined };
+ const { a = 'default' } = obj;
+ `,
+ `
+ function test(arr: number[] | undefined = []) {
+ return arr;
+ }
+ `,
+ `
+ function Bar({ nested: { foo = '' } = {} }: { nested?: { foo?: string } }) {
+ return foo;
+ }
+ `,
+ `
+ function test(a: any = 'default') {
+ return a;
+ }
+ `,
+ `
+ function test(a: unknown = 'default') {
+ return a;
+ }
+ `,
+ `
+ function test(a = 5) {
+ return a;
+ }
+ `,
+ `
+ function createValidator(): () => void {
+ return (param = 5) => {};
+ }
+ `,
+ `
+ function Bar({ foo = '' }: { foo: any }) {
+ return foo;
+ }
+ `,
+ `
+ function Bar({ foo = '' }: { foo: unknown }) {
+ return foo;
+ }
+ `,
+ `
+ function getValue(): undefined;
+ function getValue(box: { value: string }): string;
+ function getValue({ value = '' }: { value?: string } = {}): string | undefined {
+ return value;
+ }
+ `,
+ `
+ function getValueObject({ value = '' }: Partial<{ value: string }>) {
+ return value;
+ }
+ `,
+ `
+ const { value = 'default' } = someUnknownFunction();
+ `,
+ `
+ const [value = 'default'] = someUnknownFunction();
+ `,
+ `
+ for (const { value = 'default' } of []) {
+ }
+ `,
+ `
+ for (const [value = 'default'] of []) {
+ }
+ `,
+ `
+ declare const x: [[number | undefined]];
+ const [[a = 1]] = x;
+ `,
+ `
+ function foo(x: string = '') {}
+ `,
+ `
+ class C {
+ method(x: string = '') {}
+ }
+ `,
+ `
+ const foo = (x: string = '') => {};
+ `,
+ `
+ const obj = { ab: { x: 1 } };
+ const {
+ ['a' + 'b']: { x = 1 },
+ } = obj;
+ `,
+ `
+ const obj = { ab: 1 };
+ const { ['a' + 'b']: x = 1 } = obj;
+ `,
+ `
+ for ([[a = 1]] of []) {
+ }
+ `,
+ {
+ code: `
+ declare const g: Array;
+ const [foo = ''] = g;
+ `,
+ languageOptions: {
+ parserOptions: {
+ project: './tsconfig.noUncheckedIndexedAccess.json',
+ projectService: false,
+ tsconfigRootDir: rootDir,
+ },
+ },
+ },
+ {
+ code: `
+ declare const g: Record;
+ const { foo = '' } = g;
+ `,
+ languageOptions: {
+ parserOptions: {
+ project: './tsconfig.noUncheckedIndexedAccess.json',
+ projectService: false,
+ tsconfigRootDir: rootDir,
+ },
+ },
+ },
+ {
+ code: `
+ declare const h: { [key: string]: string };
+ const { bar = '' } = h;
+ `,
+ languageOptions: {
+ parserOptions: {
+ project: './tsconfig.noUncheckedIndexedAccess.json',
+ projectService: false,
+ tsconfigRootDir: rootDir,
+ },
+ },
+ },
+ ],
+ invalid: [
+ {
+ code: `
+ function Bar({ foo = '' }: { foo: string }) {
+ return foo;
+ }
+ `,
+ errors: [
+ {
+ column: 30,
+ data: { type: 'property' },
+ endColumn: 32,
+ line: 2,
+ messageId: 'uselessDefaultAssignment',
+ },
+ ],
+ output: `
+ function Bar({ foo }: { foo: string }) {
+ return foo;
+ }
+ `,
+ },
+ {
+ code: `
+ class C {
+ public method({ foo = '' }: { foo: string }) {
+ return foo;
+ }
+ }
+ `,
+ errors: [
+ {
+ column: 33,
+ data: { type: 'property' },
+ endColumn: 35,
+ line: 3,
+ messageId: 'uselessDefaultAssignment',
+ },
+ ],
+ output: `
+ class C {
+ public method({ foo }: { foo: string }) {
+ return foo;
+ }
+ }
+ `,
+ },
+ {
+ code: `
+ const { 'literal-key': literalKey = 'default' } = { 'literal-key': 'value' };
+ `,
+ errors: [
+ {
+ column: 45,
+ data: { type: 'property' },
+ endColumn: 54,
+ line: 2,
+ messageId: 'uselessDefaultAssignment',
+ },
+ ],
+ output: `
+ const { 'literal-key': literalKey } = { 'literal-key': 'value' };
+ `,
+ },
+ {
+ code: `
+ [1, 2, 3].map((a = 42) => a + 1);
+ `,
+ errors: [
+ {
+ column: 28,
+ data: { type: 'parameter' },
+ endColumn: 30,
+ line: 2,
+ messageId: 'uselessDefaultAssignment',
+ },
+ ],
+ output: `
+ [1, 2, 3].map((a) => a + 1);
+ `,
+ },
+ {
+ code: `
+ function getValue(): undefined;
+ function getValue(box: { value: string }): string;
+ function getValue({ value = '' }: { value: string } = {}): string | undefined {
+ return value;
+ }
+ `,
+ errors: [
+ {
+ column: 37,
+ data: { type: 'property' },
+ endColumn: 39,
+ line: 4,
+ messageId: 'uselessDefaultAssignment',
+ },
+ ],
+ output: `
+ function getValue(): undefined;
+ function getValue(box: { value: string }): string;
+ function getValue({ value }: { value: string } = {}): string | undefined {
+ return value;
+ }
+ `,
+ },
+ {
+ code: `
+ function getValue([value = '']: [string]) {
+ return value;
+ }
+ `,
+ errors: [
+ {
+ column: 36,
+ data: { type: 'property' },
+ endColumn: 38,
+ line: 2,
+ messageId: 'uselessDefaultAssignment',
+ },
+ ],
+ output: `
+ function getValue([value]: [string]) {
+ return value;
+ }
+ `,
+ },
+ {
+ code: `
+ declare const x: { hello: { world: string } };
+
+ const {
+ hello: { world = '' },
+ } = x;
+ `,
+ errors: [
+ {
+ column: 28,
+ data: { type: 'property' },
+ endColumn: 30,
+ line: 5,
+ messageId: 'uselessDefaultAssignment',
+ },
+ ],
+ output: `
+ declare const x: { hello: { world: string } };
+
+ const {
+ hello: { world },
+ } = x;
+ `,
+ },
+ {
+ code: `
+ declare const x: { hello: Array<{ world: string }> };
+
+ const {
+ hello: [{ world = '' }],
+ } = x;
+ `,
+ errors: [
+ {
+ column: 29,
+ data: { type: 'property' },
+ endColumn: 31,
+ line: 5,
+ messageId: 'uselessDefaultAssignment',
+ },
+ ],
+ output: `
+ declare const x: { hello: Array<{ world: string }> };
+
+ const {
+ hello: [{ world }],
+ } = x;
+ `,
+ },
+ {
+ code: `
+ interface B {
+ foo: (b: boolean | string) => void;
+ }
+
+ const h: B = {
+ foo: (b = false) => {},
+ };
+ `,
+ errors: [
+ {
+ column: 21,
+ data: { type: 'parameter' },
+ endColumn: 26,
+ line: 7,
+ messageId: 'uselessDefaultAssignment',
+ },
+ ],
+ output: `
+ interface B {
+ foo: (b: boolean | string) => void;
+ }
+
+ const h: B = {
+ foo: (b) => {},
+ };
+ `,
+ },
+ {
+ code: `
+ function foo(a = undefined) {}
+ `,
+ errors: [
+ {
+ column: 26,
+ data: { type: 'parameter' },
+ endColumn: 35,
+ line: 2,
+ messageId: 'uselessUndefined',
+ },
+ ],
+ output: `
+ function foo(a) {}
+ `,
+ },
+ {
+ code: `
+ const { a = undefined } = {};
+ `,
+ errors: [
+ {
+ column: 21,
+ data: { type: 'property' },
+ endColumn: 30,
+ line: 2,
+ messageId: 'uselessUndefined',
+ },
+ ],
+ output: `
+ const { a } = {};
+ `,
+ },
+ {
+ code: `
+ const [a = undefined] = [];
+ `,
+ errors: [
+ {
+ column: 20,
+ data: { type: 'property' },
+ endColumn: 29,
+ line: 2,
+ messageId: 'uselessUndefined',
+ },
+ ],
+ output: `
+ const [a] = [];
+ `,
+ },
+ {
+ code: `
+ function foo({ a = undefined }) {}
+ `,
+ errors: [
+ {
+ column: 28,
+ data: { type: 'property' },
+ endColumn: 37,
+ line: 2,
+ messageId: 'uselessUndefined',
+ },
+ ],
+ output: `
+ function foo({ a }) {}
+ `,
+ },
+ {
+ code: `
+ declare const g: Record;
+ const { hello = '' } = g;
+ `,
+ errors: [
+ {
+ column: 25,
+ data: { type: 'property' },
+ endColumn: 27,
+ line: 3,
+ messageId: 'uselessDefaultAssignment',
+ },
+ ],
+ output: `
+ declare const g: Record;
+ const { hello } = g;
+ `,
+ },
+ {
+ code: `
+ declare const h: { [key: string]: string };
+ const { world = '' } = h;
+ `,
+ errors: [
+ {
+ column: 25,
+ data: { type: 'property' },
+ endColumn: 27,
+ line: 3,
+ messageId: 'uselessDefaultAssignment',
+ },
+ ],
+ output: `
+ declare const h: { [key: string]: string };
+ const { world } = h;
+ `,
+ },
+ {
+ code: `
+ declare const g: Array;
+ const [foo = ''] = g;
+ `,
+ errors: [
+ {
+ column: 22,
+ data: { type: 'property' },
+ endColumn: 24,
+ line: 3,
+ messageId: 'uselessDefaultAssignment',
+ },
+ ],
+ output: `
+ declare const g: Array;
+ const [foo] = g;
+ `,
+ },
+ ],
+});
diff --git a/packages/eslint-plugin/tests/schema-snapshots/no-useless-default-assignment.shot b/packages/eslint-plugin/tests/schema-snapshots/no-useless-default-assignment.shot
new file mode 100644
index 000000000000..cdd9f8375858
--- /dev/null
+++ b/packages/eslint-plugin/tests/schema-snapshots/no-useless-default-assignment.shot
@@ -0,0 +1,10 @@
+
+# SCHEMA:
+
+[]
+
+
+# TYPES:
+
+/** No options declared */
+type Options = [];