@@ -42,6 +42,7 @@ export default defineConfig(
4242 {
4343 name : 'eslint overrides' ,
4444 rules : {
45+ curly : [ 'error' , 'all' ] ,
4546 eqeqeq : [ 'error' , 'always' , { null : 'ignore' } ] ,
4647 'logical-assignment-operators' : 'error' ,
4748 'no-else-return' : 'error' ,
@@ -265,6 +266,127 @@ export default defineConfig(
265266 '@typescript-eslint/no-throw-literal' : 'off' ,
266267 'unicorn/no-array-reduce' : 'off' ,
267268 } ,
268- }
269+ } ,
269270 //#endregion
271+
272+ {
273+ name : 'custom' ,
274+ plugins : {
275+ custom : {
276+ rules : {
277+ 'no-arrow-parameter-types' : {
278+ meta : {
279+ fixable : 'code' ,
280+ hasSuggestions : true ,
281+ type : 'suggestion' ,
282+ dialects : [ 'typescript' ] ,
283+ schema : [
284+ {
285+ type : 'object' ,
286+ properties : {
287+ allowOptional : {
288+ type : 'boolean' ,
289+ default : false ,
290+ description :
291+ 'Allow type annotations when the parameter is optional. Sometimes useful for overloaded functions.' ,
292+ } ,
293+ } ,
294+ } ,
295+ ] ,
296+ defaultOptions : [
297+ {
298+ allowOptional : false ,
299+ } ,
300+ ] ,
301+ } ,
302+ create ( context ) {
303+ const options = context . options [ 0 ] as { allowOptional : boolean } ;
304+
305+ return {
306+ ArrowFunctionExpression ( node ) {
307+ const paramsWithTypeAnnotation = node . params . filter (
308+ (
309+ // @ts -expect-error: will be inferred when moved into an official plugin
310+ param
311+ ) => param . typeAnnotation !== undefined
312+ ) ;
313+
314+ const isCatchClause =
315+ node . parent . callee ?. property ?. name === 'catch' ;
316+
317+ if ( paramsWithTypeAnnotation . length > 0 && ! isCatchClause ) {
318+ for ( const param of paramsWithTypeAnnotation ) {
319+ if ( param . optional && options . allowOptional ) {
320+ continue ;
321+ }
322+
323+ context . report ( {
324+ node : param ,
325+ message :
326+ 'Arrow function parameters should not have type annotations. Instead the Object where the operation is used should be typed correctly.' ,
327+ fix ( fixer ) {
328+ if ( param . optional ) {
329+ return null ;
330+ }
331+
332+ // TODO @Shinigami 92 2025-06-16: Handle async arrow functions
333+ if ( node . parent . type === 'VariableDeclarator' ) {
334+ const variableDeclaratorNode = node . parent ;
335+
336+ return [
337+ // Remove ` =>`
338+ fixer . replaceTextRange (
339+ [ node . body . range [ 0 ] - 3 , node . body . range [ 0 ] ] ,
340+ ''
341+ ) ,
342+ // Remove ` = `
343+ fixer . replaceTextRange (
344+ [
345+ variableDeclaratorNode . id . range [ 1 ] ,
346+ variableDeclaratorNode . init . range [ 0 ] ,
347+ ] ,
348+ ''
349+ ) ,
350+ // Replace `const ` with `function `
351+ fixer . replaceTextRange (
352+ [
353+ variableDeclaratorNode . parent . range [ 0 ] ,
354+ variableDeclaratorNode . range [ 0 ] ,
355+ ] ,
356+ 'function '
357+ ) ,
358+ ] ;
359+ }
360+
361+ return fixer . removeRange ( param . typeAnnotation . range ) ;
362+ } ,
363+ suggest : [
364+ {
365+ desc : 'Remove type annotation' ,
366+ fix ( fixer ) {
367+ if ( param . optional ) {
368+ return fixer . removeRange ( [
369+ param . typeAnnotation . range [ 0 ] - 1 , // Remove the `?` before the type annotation
370+ param . typeAnnotation . range [ 1 ] ,
371+ ] ) ;
372+ }
373+
374+ return null ;
375+ } ,
376+ } ,
377+ ] ,
378+ } ) ;
379+ }
380+ }
381+ } ,
382+ } ;
383+ } ,
384+ } ,
385+ } ,
386+ } ,
387+ } ,
388+ rules : {
389+ 'custom/no-arrow-parameter-types' : [ 'error' , { allowOptional : true } ] ,
390+ } ,
391+ }
270392) ;
0 commit comments