member-ordering
Require a consistent member declaration order.
This rule aims to standardize the way classes, interfaces, and type literals are structured and ordered. A consistent ordering of fields, methods and constructors can make code easier to read, navigate, and edit.
This rule is feature frozen: it will no longer receive new features such as new options. It still will accept bug and documentation fixes for its existing area of features.
Stylistic rules that enforce naming and/or sorting conventions tend to grow incomprehensibly complex as increasingly obscure features are requested. This rule has reached the limit of what is reasonable for the typescript-eslint project to maintain. See eslint-plugin: Feature freeze naming and sorting stylistic rules for more information.
module.exports = {
"rules": {
"@typescript-eslint/member-ordering": "error"
}
};
Try this rule in the playground ↗
Options
interface Options {
default?: OrderConfig;
classes?: OrderConfig;
classExpressions?: OrderConfig;
interfaces?: OrderConfig;
typeLiterals?: OrderConfig;
}
type OrderConfig = MemberType[] | SortedOrderConfig | 'never';
interface SortedOrderConfig {
memberTypes?: MemberType[] | 'never';
optionalityOrder?: 'optional-first' | 'required-first';
order?:
| 'alphabetically'
| 'alphabetically-case-insensitive'
| 'as-written'
| 'natural'
| 'natural-case-insensitive';
}
// See below for the more specific MemberType strings
type MemberType = string | string[];
You can configure OrderConfig
options for:
default
: all constructs (used as a fallback)classes
?: override ordering specifically for classesclassExpressions
?: override ordering specifically for class expressionsinterfaces
?: override ordering specifically for interfacestypeLiterals
?: override ordering specifically for type literals
The OrderConfig
settings for each kind of construct may configure sorting on up to three levels:
memberTypes
: organizing on member type groups such as methods vs. propertiesoptionalityOrder
: whether to put all optional members first or all required members firstorder
: organizing based on member names, such as alphabetically
Groups
You can define many different groups based on different attributes of members. The supported member attributes are, in order:
- Accessibility (
'public' | 'protected' | 'private' | '#private'
) - Decoration (
'decorated'
): Whether the member has an explicit accessibility decorator - Kind (
'call-signature' | 'constructor' | 'field' | 'readonly-field' | 'get' | 'method' | 'set' | 'signature' | 'readonly-signature'
)
Member attributes may be joined with a '-'
to combine into more specific groups.
For example, 'public-field'
would come before 'private-field'
.
Orders
The order
value specifies what order members should be within a group.
It defaults to as-written
, meaning any order is fine.
Other allowed values are:
alphabetically
: Sorted in a-z alphabetical order, directly using string<
comparison (soB
comes beforea
)alphabetically-case-insensitive
: Sorted in a-z alphabetical order, ignoring case (soa
comes beforeB
)natural
: Same asalphabetically
, but usingnatural-compare-lite
for more friendly sorting of numbersnatural-case-insensitive
: Same asalphabetically-case-insensitive
, but usingnatural-compare-lite
for more friendly sorting of numbers
Default configuration
The default configuration looks as follows:
{
"default": {
"memberTypes": [
// Index signature
"signature",
"call-signature",
// Fields
"public-static-field",
"protected-static-field",
"private-static-field",
"#private-static-field",
"public-decorated-field",
"protected-decorated-field",
"private-decorated-field",
"public-instance-field",
"protected-instance-field",
"private-instance-field",
"#private-instance-field",
"public-abstract-field",
"protected-abstract-field",
"public-field",
"protected-field",
"private-field",
"#private-field",
"static-field",
"instance-field",
"abstract-field",
"decorated-field",
"field",
// Static initialization
"static-initialization",
// Constructors
"public-constructor",
"protected-constructor",
"private-constructor",
"constructor",
// Accessors
"public-static-accessor",
"protected-static-accessor",
"private-static-accessor",
"#private-static-accessor",
"public-decorated-accessor",
"protected-decorated-accessor",
"private-decorated-accessor",
"public-instance-accessor",
"protected-instance-accessor",
"private-instance-accessor",
"#private-instance-accessor",
"public-abstract-accessor",
"protected-abstract-accessor",
"public-accessor",
"protected-accessor",
"private-accessor",
"#private-accessor",
"static-accessor",
"instance-accessor",
"abstract-accessor",
"decorated-accessor",
"accessor",
// Getters
"public-static-get",
"protected-static-get",
"private-static-get",
"#private-static-get",
"public-decorated-get",
"protected-decorated-get",
"private-decorated-get",
"public-instance-get",
"protected-instance-get",
"private-instance-get",
"#private-instance-get",
"public-abstract-get",
"protected-abstract-get",
"public-get",
"protected-get",
"private-get",
"#private-get",
"static-get",
"instance-get",
"abstract-get",
"decorated-get",
"get",
// Setters
"public-static-set",
"protected-static-set",
"private-static-set",
"#private-static-set",
"public-decorated-set",
"protected-decorated-set",
"private-decorated-set",
"public-instance-set",
"protected-instance-set",
"private-instance-set",
"#private-instance-set",
"public-abstract-set",
"protected-abstract-set",
"public-set",
"protected-set",
"private-set",
"#private-set",
"static-set",
"instance-set",
"abstract-set",
"decorated-set",
"set",
// Methods
"public-static-method",
"protected-static-method",
"private-static-method",
"#private-static-method",
"public-decorated-method",
"protected-decorated-method",
"private-decorated-method",
"public-instance-method",
"protected-instance-method",
"private-instance-method",
"#private-instance-method",
"public-abstract-method",
"protected-abstract-method",
"public-method",
"protected-method",
"private-method",
"#private-method",
"static-method",
"instance-method",
"abstract-method",
"decorated-method",
"method",
],
},
}
The default configuration contains member group types which contain other member types. This is intentional to provide better error messages.
By default, the members are not sorted. If you want to sort them alphabetically, you have to provide a custom configuration.
Examples
General Order on All Constructs
This config specifies the order for all constructs. It ignores member types other than signatures, methods, constructors, and fields. It also ignores accessibility and scope.
// .eslintrc.json
{
"rules": {
"@typescript-eslint/member-ordering": [
"error",
{ "default": ["signature", "method", "constructor", "field"] },
],
},
}
- ❌ Incorrect
- ✅ Correct
interface Foo {
B: string; // -> field
new (); // -> constructor
A(): void; // -> method
[Z: string]: any; // -> signature
}
Open in Playgroundtype Foo = {
B: string; // -> field
// no constructor
A(): void; // -> method
// no signature
};
Open in Playgroundclass 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
[Z: string]: any; // -> signature
}
Open in Playgroundconst Foo = class {
private C: string; // -> field
public D: string; // -> field
constructor() {} // -> constructor
public static A(): void {} // -> method
public B(): void {} // -> method
[Z: string]: any; // -> signature
protected static E: string; // -> field
};
Open in Playgroundinterface Foo {
[Z: string]: any; // -> signature
A(): void; // -> method
new (); // -> constructor
B: string; // -> field
}
Open in Playgroundtype Foo = {
// no signature
A(): void; // -> method
// no constructor
B: string; // -> field
};
Open in Playgroundclass Foo {
[Z: string]: any; // -> signature
public static A(): void {} // -> method
public B(): void {} // -> method
constructor() {} // -> constructor
private C: string; // -> field
public D: string; // -> field
protected static E: string; // -> field
}
Open in Playgroundconst Foo = class {
[Z: string]: any; // -> signature
public static A(): void {} // -> method
public B(): void {} // -> method
constructor() {} // -> constructor
private C: string; // -> field
public D: string; // -> field
protected static E: string; // -> field
};
Open in PlaygroundClasses
Public Instance Methods Before Public Static Fields
This config specifies that public instance methods should come first before public static fields. Everything else can be placed anywhere. It doesn't apply to interfaces or type literals as accessibility and scope are not part of them.
// .eslintrc.json
{
"rules": {
"@typescript-eslint/member-ordering": [
"error",
{ "default": ["public-instance-method", "public-static-field"] },
],
},
}
- ❌ Incorrect
- ✅ Correct
class Foo {
private C: string; // (irrelevant)
public D: string; // (irrelevant)
public static E: string; // -> public static field
constructor() {} // (irrelevant)
public static A(): void {} // (irrelevant)
[Z: string]: any; // (irrelevant)
public B(): void {} // -> public instance method
}
Open in Playgroundconst Foo = class {
private C: string; // (irrelevant)
[Z: string]: any; // (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
};
Open in Playgroundclass 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)
[Z: string]: any; // (irrelevant)
}
Open in Playgroundconst Foo = class {
public B(): void {} // -> public instance method
private C: string; // (irrelevant)
[Z: string]: any; // (irrelevant)
public D: string; // (irrelevant)
constructor() {} // (irrelevant)
public static A(): void {} // (irrelevant)
public static E: string; // -> public static field
};
Open in PlaygroundStatic Fields Before Instance Fields
This config specifies that static fields should come before instance fields, with public static fields first. It doesn't apply to interfaces or type literals as accessibility and scope are not part of them.
{
"rules": {
"@typescript-eslint/member-ordering": [
"error",
{ "default": ["public-static-field", "static-field", "instance-field"] },
],
},
}
- ❌ Incorrect
- ✅ Correct
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
[Z: string]: any; // (irrelevant)
}
Open in Playgroundconst foo = class {
public T(): void {} // method (irrelevant)
private static B: string; // -> static field
constructor() {} // constructor (irrelevant)
private E: string; // -> instance field
protected static C: string; // -> static field
private static D: string; // -> static field
[Z: string]: any; // signature (irrelevant)
public static A: string; // -> public static field
};
Open in Playgroundclass 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
[Z: string]: any; // (irrelevant)
}
Open in Playgroundconst foo = class {
[Z: string]: any; // -> signature (irrelevant)
public static A: string; // -> public static field
constructor() {} // -> constructor (irrelevant)
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 (irrelevant)
};
Open in PlaygroundClass Declarations
This config only specifies an order for classes: methods, then the constructor, then fields.
It does not apply to class expressions (use classExpressions
for them).
Default settings will be used for class declarations and all other syntax constructs other than class declarations.
// .eslintrc.json
{
"rules": {
"@typescript-eslint/member-ordering": [
"error",
{ "classes": ["method", "constructor", "field"] },
],
},
}
- ❌ Incorrect
- ✅ Correct
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
}
Open in Playgroundclass 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
}
Open in PlaygroundClass Expressions
This config only specifies an order for classes expressions: methods, then the constructor, then fields.
It does not apply to class declarations (use classes
for them).
Default settings will be used for class declarations and all other syntax constructs other than class expressions.
// .eslintrc.json
{
"rules": {
"@typescript-eslint/member-ordering": [
"error",
{ "classExpressions": ["method", "constructor", "field"] },
],
},
}
- ❌ Incorrect
- ✅ Correct
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
};
Open in Playgroundconst 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
};
Open in PlaygroundInterfaces
This config only specifies an order for interfaces: signatures, then methods, then constructors, then fields.
It does not apply to type literals (use typeLiterals
for them).
Default settings will be used for type literals and all other syntax constructs other than class expressions.
These member types are the only ones allowed for interfaces
.
// .eslintrc.json
{
"rules": {
"@typescript-eslint/member-ordering": [
"error",
{ "interfaces": ["signature", "method", "constructor", "field"] },
],
},
}
- ❌ Incorrect
- ✅ Correct
interface Foo {
B: string; // -> field
new (); // -> constructor
A(): void; // -> method
[Z: string]: any; // -> signature
}
Open in Playgroundinterface Foo {
[Z: string]: any; // -> signature
A(): void; // -> method
new (); // -> constructor
B: string; // -> field
}
Open in PlaygroundType Literals
This config only specifies an order for type literals: signatures, then methods, then constructors, then fields.
It does not apply to interfaces (use interfaces
for them).
Default settings will be used for interfaces and all other syntax constructs other than class expressions.
These member types are the only ones allowed for typeLiterals
.
// .eslintrc.json
{
"rules": {
"@typescript-eslint/member-ordering": [
"error",
{ "typeLiterals": ["signature", "method", "constructor", "field"] },
],
},
}
- ❌ Incorrect
- ✅ Correct
type Foo = {
B: string; // -> field
A(): void; // -> method
new (); // -> constructor
[Z: string]: any; // -> signature
};
Open in Playgroundtype Foo = {
[Z: string]: any; // -> signature
A(): void; // -> method
new (); // -> constructor
B: string; // -> field
};
Open in PlaygroundSorting Options
Sorting Alphabetically Within Member Groups
The default member order will be applied if memberTypes
is not specified.
You can see the default order in Default Configuration.
// .eslintrc.json
{
"rules": {
"@typescript-eslint/member-ordering": [
"error",
{
"default": {
"order": "alphabetically",
},
},
],
},
}
- ❌ Incorrect
- ✅ Correct
interface Foo {
a: x;
B: x;
c: x;
B(): void;
c(): void;
a(): void;
}
Open in Playgroundinterface Foo {
B: x;
a: x;
c: x;
B(): void;
a(): void;
c(): void;
}
Open in PlaygroundSorting Alphabetically Within Custom Member Groups
This config specifies that within each custom memberTypes
group, members are in an alphabetic case-sensitive order.
// .eslintrc.json
{
"rules": {
"@typescript-eslint/member-ordering": [
"error",
{
"default": {
"memberTypes": ["method", "field"],
"order": "alphabetically",
},
},
],
},
}
- ❌ Incorrect
- ✅ Correct
interface Foo {
B(): void;
c(): void;
a(): void;
a: x;
B: x;
c: x;
}
Open in Playgroundinterface Foo {
B(): void;
a(): void;
c(): void;
B: x;
a: x;
c: x;
}
Open in Playground