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.
Note: The default
options are overwritten in these examples.
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
};
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
};
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
};
Note: 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).
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
}
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
}
Note: 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).
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
};
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)
};
Note: 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).
interface Foo {
B: string; // -> field
new (); // -> constructor
A(): void; // -> method
}
interface Foo {
A(): void; // -> method
new (); // -> constructor
B: string; // -> field
}
Note: 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).
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.
- TSLint: member-ordering