src/content/docs/linter/rules/use-consistent-method-signatures.mdx
import { Tabs, TabItem } from '@astrojs/starlight/components';
<Tabs> <TabItem label="TypeScript and TSX" icon="seti:typescript"> :::caution This rule is part of the [nursery](/linter/#nursery) group. This means that it is experimental and the behavior can change at any time. ::: ## Summary - Rule available since: `v2.3.14` - Diagnostic Category: [`lint/nursery/useConsistentMethodSignatures`](/reference/diagnostics#diagnostic-category) - This rule doesn't have a fix. - The default severity of this rule is [**information**](/reference/diagnostics#information). - Sources: - Same as [`@typescript-eslint/method-signature-style`](https://typescript-eslint.io/rules/method-signature-style){
"linter": {
"rules": {
"nursery": {
"useConsistentMethodSignatures": "error"
}
}
}
}
Enforce consistent use of either method signatures or function properties within interfaces and type aliases.
TypeScript provides 2 different ways to declare methods within interfaces and object types:
interface Example {
// method shorthand syntax
methodFunc(arg: string): void;
// regular property with function type
prop: (arg: string) => void;
}
// These forms correspond to the analogous JS object literal patterns:
const obj = {
methodFunc(arg) {},
prop: (arg) => {},
} satisfies Example;
While mostly a matter of stylistic consistency, the two gain subtle differences in behavior when the
strictFunctionTypes compiler option is enabled.
More specifically, its stricter contravariant checks will only apply to functions written in property syntax — ones written as methods will remain with the weaker bivariant type checks.
<details> <summary>What's the difference?</summary> To illustrate the differences between method bivariance and contravariance, consider the following snippet of code:interface Emitter {
methodFunc(arg: Event): void;
propFunc: (arg: Event) => void;
}
interface SpecialEvent extends Event {
isBirthday: boolean;
}
interface SpecialEmitter extends Emitter {
methodFunc(arg: SpecialEvent): void; // OK
propFunc: (arg: SpecialEvent) => void; // Error under `strictFunctionTypes`
}
In the above example, SpecialEmitter.methodFunc is compatible with Emitter.methodFunc under bivariant1 checks,
as SpecialEvent is assignable to Event (i.e. all SpecialEvents are guaranteed to be valid Events).
On the other hand, the strict contravariant checks for function properties produce errors on propFunc as the reverse is not guaranteed —
Event is not assignable to SpecialEvent (i.e. not all Events are guaranteed to be valid SpecialEvents).
The full rationale for this behavior can be found in the TypeScript handbook.
In practice, this is only true for pathological types like type T<A> = number,
and so is often used to refer to a type being either covariant or contravariant (which simply requires T<A> and T<B> to have some non-zero amount of overlap).
:::info
Without strictFunctionTypes enabled, method signatures and function properties become functionally identical.
In this case, which option to use simply becomes a matter of personal preference.
:::
interface Example {
methodFunc(arg: string): number;
}
type Generic<T, U> = {
methodFunc(arg: T): U;
}
type Union =
| {
foo(bar: number): number;
}
| 4;
type Intersection =
{
qux(quux: number): "quuux";
} & { foo: string };
interface Prop {
propFunc: (arg: string) => number;
}
type Thing<T> = {
genericProp: <U>(arg: U) => T;
}
type Callback = () => void;
Classes (as well as interfaces lacking function declarations) are always ignored:
interface Example {
notAFunc: number;
}
class Foo {
methodFunc(arg: string): number;
}
styleThe desired method signature style to enforce.
Possible values are either "method" or "property".
Default: "property"2
"style": "method"{
"linter": {
"rules": {
"nursery": {
"useConsistentMethodSignatures": {
"options": {
"style": "method"
}
}
}
}
}
}
interface Blah {
propFunc: (arg: string) => void;
}
type Generic = {
propFunc: <T, U>(arg: T) => U;
}
type OK = {
flubber(arg: number): number;
}