A consistent ordering of fields, methods and constructors can make interfaces, type literals, classes and class expressions easier to read, navigate and edit.
This rule aims to standardize the way class declarations, class expressions, interfaces and type literals are structured.
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.
{ default?: Array<MemberType> | never classes?: Array<MemberType> | never classExpressions?: Array<MemberType> | never interfaces?: ['field' | 'method' | 'constructor'] | never typeLiterals?: ['field' | 'method' | 'constructor'] | never }
See below for the possible definitions of MemberType
.
There are multiple ways to specify the member types. The most explicit and granular form is the following:
[ // Fields 'public-static-field', 'protected-static-field', 'private-static-field', 'public-instance-field', 'protected-instance-field', 'private-instance-field', // Constructors 'public-constructor', 'protected-constructor', 'private-constructor', // Methods 'public-static-method', 'protected-static-method', 'private-static-method', 'public-instance-method', 'protected-instance-method', 'private-instance-method', ]
Note: If you only specify some of the possible types, the non-specified ones can have any particular order. This means that they can be placed before, within or after the specified types and the linter won't complain about it.
It is also possible to group member types by their accessibility (static
, instance
), ignoring their scope.
[ // Fields 'public-field', // = ['public-static-field', 'public-instance-field']) 'protected-field', // = ['protected-static-field', 'protected-instance-field']) 'private-field', // = ['private-static-field', 'private-instance-field']) // Constructors // Only the accessibility of constructors is configurable. See below. // Methods 'public-method', // = ['public-static-method', 'public-instance-method']) 'protected-method', // = ['protected-static-method', 'protected-instance-method']) 'private-method', // = ['private-static-method', 'private-instance-method']) ]
Another option is to group the member types by their scope (public
, protected
, private
), ignoring their accessibility.
[ // Fields 'static-field', // = ['public-static-field', 'protected-static-field', 'private-static-field']) 'instance-field', // = ['public-instance-field', 'protected-instance-field', 'private-instance-field']) // Constructors 'constructor', // = ['public-constructor', 'protected-constructor', 'private-constructor']) // Methods 'static-method', // = ['public-static-method', 'protected-static-method', 'private-static-method']) 'instance-method', // = ['public-instance-method', 'protected-instance-method', 'private-instance-method'] ]
The third grouping option is to ignore both scope and accessibility.
[ // Fields 'field', // = ['public-static-field', 'protected-static-field', 'private-static-field', 'public-instance-field', 'protected-instance-field', 'private-instance-field']) // Constructors // Only the accessibility of constructors is configurable. See above. // Methods 'method', // = ['public-static-method', 'protected-static-method', 'private-static-method', 'public-instance-method', 'protected-instance-method', 'private-instance-method']) ]
The default configuration looks as follows:
{ "default": [ "public-static-field", "protected-static-field", "private-static-field", "public-instance-field", "protected-instance-field", "private-instance-field", "public-field", "protected-field", "private-field", "static-field", "instance-field", "field", "constructor", "public-static-method", "protected-static-method", "private-static-method", "public-instance-method", "protected-instance-method", "private-instance-method", "public-method", "protected-method", "private-method", "static-method", "instance-method", "method" ] }
Note: The default configuration contains member group types which contain other member types (see above). This is intentional to provide better error messages.
default
configurationNote: The default
options are overwritten in these examples.
{ "default": ["method", "constructor", "field"] }
interface Foo { B: string; // -> field new (); // -> constructor A(): void; // -> method }
Note: Wrong order.
type Foo = { B: string; // -> field // no constructor A(): void; // -> method };
Note: Not all specified member types have to exist.
class Foo { private C: string; // -> field public D: string; // -> field protected static E: string; // -> field constructor() {} // -> constructor public static A(): void {} // -> method public B(): void {} // -> method }
Note: Accessibility or scope are ignored with this ignored.
const Foo = class { private C: string; // -> field public D: string; // -> field constructor() {} // -> constructor public static A(): void {} // -> method public B(): void {} // -> method protected static E: string; // -> field };
Note: Not all members have to be grouped to find rule violations.
interface Foo { A(): void; // -> method new (); // -> constructor B: string; // -> field }
type Foo = { A(): void; // -> method // no constructor B: string; // -> field };
class Foo { public static A(): void {} // -> method public B(): void {} // -> method constructor() {} // -> constructor private C: string; // -> field public D: string; // -> field protected static E: string; // -> field }
const Foo = class { public static A(): void {} // -> method public B(): void {} // -> method constructor() {} // -> constructor private C: string; // -> field public D: string; // -> field protected static E: string; // -> field };
{ "default": ["public-instance-method", "public-static-field"] }
Note: This configuration does not apply to interfaces/type literals as accessibility and scope are not part of interfaces/type literals.
class Foo { private C: string; // (irrelevant) public D: string; // (irrelevant) public static E: string; // -> public static field constructor() {} // (irrelevant) public static A(): void {} // (irrelevant) public B(): void {} // -> public instance method }
Note: Public instance methods should come first before public static fields. Everything else can be placed anywhere.
const Foo = class { private C: string; // (irrelevant) public static E: string; // -> public static field public D: string; // (irrelevant) constructor() {} // (irrelevant) public static A(): void {} // (irrelevant) public B(): void {} // -> public instance method };
Note: Public instance methods should come first before public static fields. Everything else can be placed anywhere.
class Foo { public B(): void {} // -> public instance method private C: string; // (irrelevant) public D: string; // (irrelevant) public static E: string; // -> public static field constructor() {} // (irrelevant) public static A(): void {} // (irrelevant) }
const Foo = class { public B(): void {} // -> public instance method private C: string; // (irrelevant) public D: string; // (irrelevant) constructor() {} // (irrelevant) public static A(): void {} // (irrelevant) public static E: string; // -> public static field };
{ "default": ["public-static-field", "static-field", "instance-field"] }
Note: This configuration does not apply to interfaces/type literals as accessibility and scope are not part of interfaces/type literals.
class Foo { private E: string; // -> instance field private static B: string; // -> static field protected static C: string; // -> static field private static D: string; // -> static field public static A: string; // -> public static field }
Note: Public static fields should come first, followed by static fields and instance fields.
const foo = class { public T(): void {} // (irrelevant) private static B: string; // -> static field constructor() {} // (irrelevant) private E: string; // -> instance field protected static C: string; // -> static field private static D: string; // -> static field public static A: string; // -> public static field };
Issue: Public static fields should come first, followed by static fields and instance fields.
class Foo { public static A: string; // -> public static field private static B: string; // -> static field protected static C: string; // -> static field private static D: string; // -> static field private E: string; // -> instance field }
const foo = class { public static A: string; // -> public static field constructor() {} // -> constructor private static B: string; // -> static field protected static C: string; // -> static field private static D: string; // -> static field private E: string; // -> instance field public T(): void {} // -> method };
classes
configurationNote: If this is not set, the default
will automatically be applied to classes as well. If a classes
configuration is provided, only this configuration will be used for classes
(i.e. nothing will be merged with default
).
Note: The configuration for classes
does not apply to class expressions (use classExpressions
for them).
{ "classes": ["method", "constructor", "field"] }
class Foo { private C: string; // -> field public D: string; // -> field protected static E: string; // -> field constructor() {} // -> constructor public static A(): void {} // -> method public B(): void {} // -> method }
class Foo { public static A(): void {} // -> method public B(): void {} // -> method constructor() {} // -> constructor private C: string; // -> field public D: string; // -> field protected static E: string; // -> field }
{ "classes": ["public-instance-method", "public-static-field"] }
class Foo { private C: string; // (irrelevant) public D: string; // (irrelevant) public static E: string; // -> public static field constructor() {} // (irrelevant) public static A(): void {} // (irrelevant) public B(): void {} // -> public instance method }
Examples of correct code for { "classes": [...] }
option:
class Foo { private C: string; // (irrelevant) public D: string; // (irrelevant) public static E: string; // -> public static field constructor() {} // (irrelevant) public static A(): void {} // (irrelevant) public B(): void {} // -> public instance method }
classExpressions
configurationNote: If this is not set, the default
will automatically be applied to classes expressions as well. If a classExpressions
configuration is provided, only this configuration will be used for classExpressions
(i.e. nothing will be merged with default
).
Note: The configuration for classExpressions
does not apply to classes (use classes
for them).
{ "classExpressions": ["method", "constructor", "field"] }
const foo = class { private C: string; // -> field public D: string; // -> field protected static E: string; // -> field constructor() {} // -> constructor public static A(): void {} // -> method public B(): void {} // -> method };
const foo = class { public static A(): void {} // -> method public B(): void {} // -> method constructor() {} // -> constructor private C: string; // -> field public D: string; // -> field protected static E: string; // -> field };
{ "classExpressions": ["public-instance-method", "public-static-field"] }
const foo = class { private C: string; // (irrelevant) public D: string; // (irrelevant) public static E: string; // -> public static field constructor() {} // (irrelevant) public static A(): void {} // (irrelevant) public B(): void {} // -> public instance method };
const foo = class { private C: string; // (irrelevant) public D: string; // (irrelevant) public B(): void {} // -> public instance method public static E: string; // -> public static field constructor() {} // (irrelevant) public static A(): void {} // (irrelevant) };
interfaces
configurationNote: If this is not set, the default
will automatically be applied to classes expressions as well. If a interfaces
configuration is provided, only this configuration will be used for interfaces
(i.e. nothing will be merged with default
).
Note: The configuration for interfaces
only allows a limited set of member types: field
, constructor
and method
.
Note: The configuration for interfaces
does not apply to type literals (use typeLiterals
for them).
{ "interfaces": ["method", "constructor", "field"] }
interface Foo { B: string; // -> field new (); // -> constructor A(): void; // -> method }
interface Foo { A(): void; // -> method new (); // -> constructor B: string; // -> field }
typeLiterals
configurationNote: If this is not set, the default
will automatically be applied to classes expressions as well. If a typeLiterals
configuration is provided, only this configuration will be used for typeLiterals
(i.e. nothing will be merged with default
).
Note: The configuration for typeLiterals
only allows a limited set of member types: field
, constructor
and method
.
Note: The configuration for typeLiterals
does not apply to type literals (use interfaces
for them).
{ "typeLiterals": ["method", "constructor", "field"] }
type Foo = { B: string; // -> field A(): void; // -> method new (); // -> constructor };
type Foo = { A(): void; // -> method new (); // -> constructor B: string; // -> field };
If you don't care about the general structure of your classes and interfaces, then you will not need this rule.