Skip to content

Commit 485e902

Browse files
timkrautbradzacher
andauthored
feat(eslint-plugin): sort members alphabetically (typescript-eslint#263)
Co-authored-by: Brad Zacher <brad.zacher@gmail.com>
1 parent 1f0ff41 commit 485e902

File tree

4 files changed

+2958
-494
lines changed

4 files changed

+2958
-494
lines changed

packages/eslint-plugin/docs/rules/member-ordering.md

Lines changed: 151 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,54 @@
11
# Require a consistent member declaration order (`member-ordering`)
22

3-
A consistent ordering of fields, methods and constructors can make interfaces, type literals, classes and class
4-
expressions easier to read, navigate and edit.
3+
A consistent ordering of fields, methods and constructors can make interfaces, type literals, classes and class expressions easier to read, navigate and edit.
54

65
## Rule Details
76

8-
This rule aims to standardize the way class declarations, class expressions, interfaces and type literals are structured.
7+
This rule aims to standardize the way class declarations, class expressions, interfaces and type literals are structured and ordered.
98

10-
It allows to group members by their type (e.g. `public-static-field`, `protected-static-field`, `private-static-field`, `public-instance-field`, ...). By default, their order is the same inside `classes`, `classExpressions`, `interfaces` and `typeLiterals` (note: not all member types apply to `interfaces` and `typeLiterals`). It is possible to define the order for any of those individually or to change the default order for all of them by setting the `default` option.
9+
### Grouping and sorting member groups
10+
11+
It allows to group members by their type (e.g. `public-static-field`, `protected-static-field`, `private-static-field`, `public-instance-field`, ...) and enforce a certain order for these groups. By default, their order is the same inside `classes`, `classExpressions`, `interfaces` and `typeLiterals` (note: not all member types apply to `interfaces` and `typeLiterals`). It is possible to define the order for any of those individually or to change the default order for all of them by setting the `default` option.
12+
13+
### Sorting members
14+
15+
Besides grouping the members and sorting their groups, this rule also allows to sort the members themselves (e.g. `a`, `b`, `c`, ...). You have 2 options: Sort all of them while ignoring their type or sort them while respecting their types (e.g. sort all fields in an interface alphabetically).
1116

1217
## Options
1318

19+
These options allow to specify how to group the members and sort their groups.
20+
21+
- Sort groups, don't enforce member order: Use `memberTypes`
22+
- Sort members, don't enforce group order: Use `order`
23+
- Sort members within groups: Use `memberTypes` and `order`
24+
1425
```ts
26+
type TypeOptions<T> =
27+
| {
28+
memberTypes: Array<T> | 'never',
29+
order?: 'alphabetically' | 'as-written',
30+
}
31+
| {
32+
order: 'alphabetically',
33+
};
34+
1535
{
16-
default?: Array<MemberType> | never
17-
classes?: Array<MemberType> | never
18-
classExpressions?: Array<MemberType> | never
36+
default?: TypeOptions<MemberTypes>,
37+
38+
classes?: TypeOptions<MemberTypes>,
39+
classExpressions?: TypeOptions<MemberTypes>,
1940

20-
interfaces?: ['signature' | 'field' | 'method' | 'constructor'] | never
21-
typeLiterals?: ['signature' | 'field' | 'method' | 'constructor'] | never
41+
interfaces?: TypeOptions<'signature' | 'field' | 'method' | 'constructor'>,
42+
typeLiterals?: TypeOptions<'signature' | 'field' | 'method' | 'constructor'>,
2243
}
2344
```
2445

2546
See below for the possible definitions of `MemberType`.
2647

48+
### Deprecated syntax
49+
50+
Note: There is a deprecated syntax to specify the member types as an array.
51+
2752
### Member types (granular form)
2853

2954
There are multiple ways to specify the member types. The most explicit and granular form is the following:
@@ -138,62 +163,72 @@ The third grouping option is to ignore both scope and accessibility.
138163

139164
The default configuration looks as follows:
140165

141-
```json
166+
```json5
142167
{
143-
"default": [
144-
"signature",
168+
default: [
169+
// Index signature
170+
'signature',
145171

146-
"public-static-field",
147-
"protected-static-field",
148-
"private-static-field",
172+
// Fields
173+
'public-static-field',
174+
'protected-static-field',
175+
'private-static-field',
149176

150-
"public-instance-field",
151-
"protected-instance-field",
152-
"private-instance-field",
177+
'public-instance-field',
178+
'protected-instance-field',
179+
'private-instance-field',
153180

154-
"public-abstract-field",
155-
"protected-abstract-field",
156-
"private-abstract-field",
181+
'public-abstract-field',
182+
'protected-abstract-field',
183+
'private-abstract-field',
157184

158-
"public-field",
159-
"protected-field",
160-
"private-field",
185+
'public-field',
186+
'protected-field',
187+
'private-field',
161188

162-
"static-field",
163-
"instance-field",
164-
"abstract-field",
189+
'static-field',
190+
'instance-field',
191+
'abstract-field',
165192

166-
"field",
193+
'field',
167194

168-
"constructor",
195+
// Constructors
196+
'public-constructor',
197+
'protected-constructor',
198+
'private-constructor',
169199

170-
"public-static-method",
171-
"protected-static-method",
172-
"private-static-method",
200+
'constructor',
173201

174-
"public-instance-method",
175-
"protected-instance-method",
176-
"private-instance-method",
202+
// Methods
203+
'public-static-method',
204+
'protected-static-method',
205+
'private-static-method',
177206

178-
"public-abstract-method",
179-
"protected-abstract-method",
180-
"private-abstract-method",
207+
'public-instance-method',
208+
'protected-instance-method',
209+
'private-instance-method',
181210

182-
"public-method",
183-
"protected-method",
184-
"private-method",
211+
'public-abstract-method',
212+
'protected-abstract-method',
213+
'private-abstract-method',
185214

186-
"static-method",
187-
"instance-method",
188-
"abstract-method",
215+
'public-method',
216+
'protected-method',
217+
'private-method',
189218

190-
"method"
191-
]
219+
'static-method',
220+
'instance-method',
221+
'abstract-method',
222+
223+
'method',
224+
],
192225
}
193226
```
194227

195228
Note: The default configuration contains member group types which contain other member types (see above). This is intentional to provide better error messages.
196229

230+
Note: By default, the members are not sorted. If you want to sort them alphabetically, you have to provide a custom configuration.
231+
197232
## Examples
198233

199234
### Custom `default` configuration
@@ -448,7 +483,7 @@ const foo = class {
448483
};
449484
```
450485

451-
Issue: Public static fields should come first, followed by static fields and instance fields.
486+
Note: Public static fields should come first, followed by static fields and instance fields.
452487

453488
##### Correct examples
454489

@@ -542,21 +577,19 @@ class Foo {
542577

543578
##### Correct example
544579

545-
Examples of **correct** code for `{ "classes": [...] }` option:
546-
547580
```ts
548581
class Foo {
549582
private C: string; // (irrelevant)
550583

551584
public D: string; // (irrelevant)
552585

553-
public static E: string; // -> public static field
586+
public B(): void {} // -> public instance method
554587

555588
constructor() {} // (irrelevant)
556589

557590
public static A(): void {} // (irrelevant)
558591

559-
public B(): void {} // -> public instance method
592+
public static E: string; // -> public static field
560593
}
561594
```
562595

@@ -712,6 +745,73 @@ type Foo = {
712745
};
713746
```
714747

748+
### Sorting alphabetically within member groups
749+
750+
It is possible to sort all members within a group alphabetically.
751+
752+
#### Configuration: `{ default: { memberTypes: <Default Order>, order: 'alphabetically' } }`
753+
754+
This will apply the default order (see above) and enforce an alphabetic order within each group.
755+
756+
##### Incorrect examples
757+
758+
```ts
759+
interface Foo {
760+
a: x;
761+
b: x;
762+
c: x;
763+
764+
new (): Bar;
765+
(): Baz;
766+
767+
a(): void;
768+
b(): void;
769+
c(): void;
770+
771+
// Wrong group order, should be placed before all field definitions
772+
[a: string]: number;
773+
}
774+
```
775+
776+
```ts
777+
interface Foo {
778+
[a: string]: number;
779+
780+
a: x;
781+
b: x;
782+
c: x;
783+
784+
new (): Bar;
785+
(): Baz;
786+
787+
// Wrong alphabetic order within group
788+
c(): void;
789+
b(): void;
790+
a(): void;
791+
}
792+
```
793+
794+
### Sorting alphabetically while ignoring member groups
795+
796+
It is also possible to sort all members and ignore the member groups completely.
797+
798+
#### Configuration: `{ default: { memberTypes: 'never', order: 'alphabetically' } }`
799+
800+
##### Incorrect example
801+
802+
```ts
803+
interface Foo {
804+
b(): void;
805+
a: b;
806+
807+
[a: string]: number; // Order doesn't matter (no sortable identifier)
808+
new (): Bar; // Order doesn't matter (no sortable identifier)
809+
(): Baz; // Order doesn't matter (no sortable identifier)
810+
}
811+
```
812+
813+
Note: Wrong alphabetic order `b(): void` should come after `a: b`.
814+
715815
## When Not To Use It
716816

717817
If you don't care about the general structure of your classes and interfaces, then you will not need this rule.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy