|
1 | 1 | # Require a consistent member declaration order (`member-ordering`)
|
2 | 2 |
|
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. |
5 | 4 |
|
6 | 5 | ## Rule Details
|
7 | 6 |
|
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. |
9 | 8 |
|
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). |
11 | 16 |
|
12 | 17 | ## Options
|
13 | 18 |
|
| 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 | + |
14 | 25 | ```ts
|
| 26 | +type TypeOptions<T> = |
| 27 | + | { |
| 28 | + memberTypes: Array<T> | 'never', |
| 29 | + order?: 'alphabetically' | 'as-written', |
| 30 | + } |
| 31 | + | { |
| 32 | + order: 'alphabetically', |
| 33 | + }; |
| 34 | + |
15 | 35 | {
|
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>, |
19 | 40 |
|
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'>, |
22 | 43 | }
|
23 | 44 | ```
|
24 | 45 |
|
25 | 46 | See below for the possible definitions of `MemberType`.
|
26 | 47 |
|
| 48 | +### Deprecated syntax |
| 49 | + |
| 50 | +Note: There is a deprecated syntax to specify the member types as an array. |
| 51 | + |
27 | 52 | ### Member types (granular form)
|
28 | 53 |
|
29 | 54 | 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.
|
138 | 163 |
|
139 | 164 | The default configuration looks as follows:
|
140 | 165 |
|
141 |
| -```json |
| 166 | +```json5 |
142 | 167 | {
|
143 |
| - "default": [ |
144 |
| - "signature", |
| 168 | + default: [ |
| 169 | + // Index signature |
| 170 | + 'signature', |
145 | 171 |
|
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', |
149 | 176 |
|
150 |
| - "public-instance-field", |
151 |
| - "protected-instance-field", |
152 |
| - "private-instance-field", |
| 177 | + 'public-instance-field', |
| 178 | + 'protected-instance-field', |
| 179 | + 'private-instance-field', |
153 | 180 |
|
154 |
| - "public-abstract-field", |
155 |
| - "protected-abstract-field", |
156 |
| - "private-abstract-field", |
| 181 | + 'public-abstract-field', |
| 182 | + 'protected-abstract-field', |
| 183 | + 'private-abstract-field', |
157 | 184 |
|
158 |
| - "public-field", |
159 |
| - "protected-field", |
160 |
| - "private-field", |
| 185 | + 'public-field', |
| 186 | + 'protected-field', |
| 187 | + 'private-field', |
161 | 188 |
|
162 |
| - "static-field", |
163 |
| - "instance-field", |
164 |
| - "abstract-field", |
| 189 | + 'static-field', |
| 190 | + 'instance-field', |
| 191 | + 'abstract-field', |
165 | 192 |
|
166 |
| - "field", |
| 193 | + 'field', |
167 | 194 |
|
168 |
| - "constructor", |
| 195 | + // Constructors |
| 196 | + 'public-constructor', |
| 197 | + 'protected-constructor', |
| 198 | + 'private-constructor', |
169 | 199 |
|
170 |
| - "public-static-method", |
171 |
| - "protected-static-method", |
172 |
| - "private-static-method", |
| 200 | + 'constructor', |
173 | 201 |
|
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', |
177 | 206 |
|
178 |
| - "public-abstract-method", |
179 |
| - "protected-abstract-method", |
180 |
| - "private-abstract-method", |
| 207 | + 'public-instance-method', |
| 208 | + 'protected-instance-method', |
| 209 | + 'private-instance-method', |
181 | 210 |
|
182 |
| - "public-method", |
183 |
| - "protected-method", |
184 |
| - "private-method", |
| 211 | + 'public-abstract-method', |
| 212 | + 'protected-abstract-method', |
| 213 | + 'private-abstract-method', |
185 | 214 |
|
186 |
| - "static-method", |
187 |
| - "instance-method", |
188 |
| - "abstract-method", |
| 215 | + 'public-method', |
| 216 | + 'protected-method', |
| 217 | + 'private-method', |
189 | 218 |
|
190 |
| - "method" |
191 |
| - ] |
| 219 | + 'static-method', |
| 220 | + 'instance-method', |
| 221 | + 'abstract-method', |
| 222 | + |
| 223 | + 'method', |
| 224 | + ], |
192 | 225 | }
|
193 | 226 | ```
|
194 | 227 |
|
195 | 228 | Note: The default configuration contains member group types which contain other member types (see above). This is intentional to provide better error messages.
|
196 | 229 |
|
| 230 | +Note: By default, the members are not sorted. If you want to sort them alphabetically, you have to provide a custom configuration. |
| 231 | + |
197 | 232 | ## Examples
|
198 | 233 |
|
199 | 234 | ### Custom `default` configuration
|
@@ -448,7 +483,7 @@ const foo = class {
|
448 | 483 | };
|
449 | 484 | ```
|
450 | 485 |
|
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. |
452 | 487 |
|
453 | 488 | ##### Correct examples
|
454 | 489 |
|
@@ -542,21 +577,19 @@ class Foo {
|
542 | 577 |
|
543 | 578 | ##### Correct example
|
544 | 579 |
|
545 |
| -Examples of **correct** code for `{ "classes": [...] }` option: |
546 |
| - |
547 | 580 | ```ts
|
548 | 581 | class Foo {
|
549 | 582 | private C: string; // (irrelevant)
|
550 | 583 |
|
551 | 584 | public D: string; // (irrelevant)
|
552 | 585 |
|
553 |
| - public static E: string; // -> public static field |
| 586 | + public B(): void {} // -> public instance method |
554 | 587 |
|
555 | 588 | constructor() {} // (irrelevant)
|
556 | 589 |
|
557 | 590 | public static A(): void {} // (irrelevant)
|
558 | 591 |
|
559 |
| - public B(): void {} // -> public instance method |
| 592 | + public static E: string; // -> public static field |
560 | 593 | }
|
561 | 594 | ```
|
562 | 595 |
|
@@ -712,6 +745,73 @@ type Foo = {
|
712 | 745 | };
|
713 | 746 | ```
|
714 | 747 |
|
| 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 | + |
715 | 815 | ## When Not To Use It
|
716 | 816 |
|
717 | 817 | If you don't care about the general structure of your classes and interfaces, then you will not need this rule.
|
|
0 commit comments