Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5bd4c0a

Browse files
fix(eslint-plugin): [consistent-type-definitions] don't leave trailing parens when fixing type to interface (typescript-eslint#10235)
* [consistent-type-definitions] remove closing parens around a type* cov* better fixer logic* test fixer edge cases* unused imports
1 parentb347c04 commit5bd4c0a

File tree

2 files changed

+148
-24
lines changed

2 files changed

+148
-24
lines changed

‎packages/eslint-plugin/src/rules/consistent-type-definitions.ts

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
importtype{TSESLint,TSESTree}from'@typescript-eslint/utils';
22

3-
import{AST_NODE_TYPES,AST_TOKEN_TYPES}from'@typescript-eslint/utils';
3+
import{AST_NODE_TYPES}from'@typescript-eslint/utils';
44

5-
import{createRule}from'../util';
5+
import{createRule,nullThrows,NullThrowsReasons}from'../util';
66

77
exportdefaultcreateRule({
88
name:'consistent-type-definitions',
@@ -54,32 +54,45 @@ export default createRule({
5454
node:node.id,
5555
messageId:'interfaceOverType',
5656
fix(fixer){
57-
consttypeNode=node.typeParameters??node.id;
58-
constfixes:TSESLint.RuleFix[]=[];
57+
consttypeToken=nullThrows(
58+
context.sourceCode.getTokenBefore(
59+
node.id,
60+
token=>token.value==='type',
61+
),
62+
NullThrowsReasons.MissingToken('type keyword','type alias'),
63+
);
5964

60-
constfirstToken=context.sourceCode.getTokenBefore(node.id);
61-
if(firstToken){
62-
fixes.push(fixer.replaceText(firstToken,'interface'));
63-
fixes.push(
64-
fixer.replaceTextRange(
65-
[typeNode.range[1],node.typeAnnotation.range[0]],
66-
' ',
67-
),
68-
);
69-
}
65+
constequalsToken=nullThrows(
66+
context.sourceCode.getTokenBefore(
67+
node.typeAnnotation,
68+
token=>token.value==='=',
69+
),
70+
NullThrowsReasons.MissingToken('=','type alias'),
71+
);
7072

71-
constafterToken=context.sourceCode.getTokenAfter(
72-
node.typeAnnotation,
73+
constbeforeEqualsToken=nullThrows(
74+
context.sourceCode.getTokenBefore(equalsToken,{
75+
includeComments:true,
76+
}),
77+
NullThrowsReasons.MissingToken('before =','type alias'),
7378
);
74-
if(
75-
afterToken&&
76-
afterToken.type===AST_TOKEN_TYPES.Punctuator&&
77-
afterToken.value===';'
78-
){
79-
fixes.push(fixer.remove(afterToken));
80-
}
8179

82-
returnfixes;
80+
return[
81+
// replace 'type' with 'interface'.
82+
fixer.replaceText(typeToken,'interface'),
83+
84+
// delete from the = to the { of the type, and put a space to be pretty.
85+
fixer.replaceTextRange(
86+
[beforeEqualsToken.range[1],node.typeAnnotation.range[0]],
87+
' ',
88+
),
89+
90+
// remove from the closing} through the end of the statement.
91+
fixer.removeRange([
92+
node.typeAnnotation.range[1],
93+
node.range[1],
94+
]),
95+
];
8396
},
8497
});
8598
},

‎packages/eslint-plugin/tests/rules/consistent-type-definitions.test.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ export type W<T> = {
9696
options:['interface'],
9797
output:`interface T { x: number; }`,
9898
},
99+
{
100+
code:noFormat`type T /* comment */={ x: number; };`,
101+
errors:[
102+
{
103+
column:6,
104+
line:1,
105+
messageId:'interfaceOverType',
106+
},
107+
],
108+
options:['interface'],
109+
output:`interface T /* comment */ { x: number; }`,
110+
},
99111
{
100112
code:`
101113
export type W<T> = {
@@ -350,5 +362,104 @@ export declare type Test = {
350362
}
351363
`,
352364
},
365+
{
366+
code:noFormat`
367+
type Foo = ({
368+
a: string;
369+
});
370+
`,
371+
errors:[
372+
{
373+
line:2,
374+
messageId:'interfaceOverType',
375+
},
376+
],
377+
output:`
378+
interface Foo {
379+
a: string;
380+
}
381+
`,
382+
},
383+
{
384+
code:noFormat`
385+
type Foo = ((((((((({
386+
a: string;
387+
})))))))));
388+
`,
389+
errors:[
390+
{
391+
line:2,
392+
messageId:'interfaceOverType',
393+
},
394+
],
395+
output:`
396+
interface Foo {
397+
a: string;
398+
}
399+
`,
400+
},
401+
{
402+
// no closing semicolon
403+
code:noFormat`
404+
type Foo = {
405+
a: string;
406+
}
407+
`,
408+
errors:[
409+
{
410+
line:2,
411+
messageId:'interfaceOverType',
412+
},
413+
],
414+
output:`
415+
interface Foo {
416+
a: string;
417+
}
418+
`,
419+
},
420+
{
421+
// no closing semicolon; ensure we don't erase subsequent code.
422+
code:noFormat`
423+
type Foo = {
424+
a: string;
425+
}
426+
type Bar = string;
427+
`,
428+
errors:[
429+
{
430+
line:2,
431+
messageId:'interfaceOverType',
432+
},
433+
],
434+
output:`
435+
interface Foo {
436+
a: string;
437+
}
438+
type Bar = string;
439+
`,
440+
},
441+
{
442+
// no closing semicolon; ensure we don't erase subsequent code.
443+
code:noFormat`
444+
type Foo = ((({
445+
a: string;
446+
})))
447+
448+
const bar = 1;
449+
`,
450+
errors:[
451+
{
452+
line:2,
453+
messageId:'interfaceOverType',
454+
},
455+
],
456+
output:`
457+
interface Foo {
458+
a: string;
459+
}
460+
461+
const bar = 1;
462+
`,
463+
},
353464
],
354465
});

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp