prefer-type-fest-promisable
Require TypeFest Promisable<T> for sync-or-async callback contracts currently expressed as Promise<T> | T unions.
Targeted pattern scopeโ
This rule narrows matching to strict two-member Promise/base unions where Promisable<T> is the canonical replacement.
- Type unions shaped like
Promise<T> | Tin architecture-critical runtime layers.
Multi-member unions and Promise-adjacent variants stay out of scope unless they exactly match the authored pair form.
What this rule reportsโ
This rule reports strict Promise<T> | T-shaped unions that should be expressed as Promisable<T>.
- Type unions shaped like
Promise<T> | Tin architecture-critical runtime layers. - Type references that resolve to imported legacy aliases such as
MaybePromise.
Detection boundariesโ
- โ
Reports strict
Promise<T> | T/T | Promise<T>unions by default. - โ
Reports imported legacy aliases such as
MaybePromiseby default. - โ Does not report namespace-qualified aliases.
- โ Auto-fixes imported legacy alias references when replacement is syntactically safe.
- โ Does not auto-fix
Promise<T> | Tunion declarations. - โ
Enforcement surface is configurable with
enforcePromiseUnionsandenforceLegacyAliases.
Why this rule existsโ
Promisable<T> communicates intent directly, keeps callback contracts consistent, and avoids repeating equivalent sync-or-async unions throughout the codebase.
โ Incorrectโ
type HookResult = Promise<Result> | Result;
โ Correctโ
type HookResult = Promisable<Result>;
Behavior and migration notesโ
Promisable<T>captures sync-or-async return contracts in one reusable alias.- It normalizes both
Promise<T> | TandT | Promise<T>forms. - Use this alias in hook/callback contracts where callers may return either immediate or async values.
Optionsโ
This rule accepts a single options object:
type PreferTypeFestPromisableOptions = {
/**
* Whether to report imported legacy aliases such as MaybePromise.
*
* @default true
*/
enforceLegacyAliases?: boolean;
/**
* Whether to report Promise<T> | T sync-or-async unions.
*
* @default true
*/
enforcePromiseUnions?: boolean;
};
Default configuration:
{
enforceLegacyAliases: true,
enforcePromiseUnions: true,
}
Flat config setup (default behavior):
import typefest from "eslint-plugin-typefest";
export default [
{
plugins: { typefest },
rules: {
"typefest/prefer-type-fest-promisable": [
"error",
{
enforceLegacyAliases: true,
enforcePromiseUnions: true,
},
],
},
},
];
enforcePromiseUnions: falseโ
Ignores union-shaped contracts while still enforcing legacy aliases:
import typefest from "eslint-plugin-typefest";
export default [
{
plugins: { typefest },
rules: {
"typefest/prefer-type-fest-promisable": [
"error",
{
enforceLegacyAliases: true,
enforcePromiseUnions: false,
},
],
},
},
];
import type { MaybePromise } from "type-aliases";
type A = Promise<Result> | Result; // โ
Not reported
type B = MaybePromise<Result>; // โ Reported
enforceLegacyAliases: falseโ
Ignores legacy aliases while still enforcing union-shaped contracts:
import typefest from "eslint-plugin-typefest";
export default [
{
plugins: { typefest },
rules: {
"typefest/prefer-type-fest-promisable": [
"error",
{
enforceLegacyAliases: false,
enforcePromiseUnions: true,
},
],
},
},
];
import type { MaybePromise } from "type-aliases";
type A = MaybePromise<Result>; // โ
Not reported
type B = Promise<Result> | Result; // โ Reported
Additional examplesโ
โ Incorrect โ Additional exampleโ
type MaybeAsync = Result | Promise<Result>;
โ Correct โ Additional exampleโ
type MaybeAsync = Promisable<Result>;
โ Correct โ Repository-wide usageโ
type HookOutput = Promisable<void>;
ESLint flat config exampleโ
import typefest from "eslint-plugin-typefest";
export default [
{
plugins: { typefest },
rules: {
"typefest/prefer-type-fest-promisable": "error",
},
},
];
When not to use itโ
Disable this rule if runtime policy requires explicitly spelling out promise unions.
Package documentationโ
TypeFest package documentation:
Source file: source/promisable.d.ts
/**
Create a type that represents either the value or the value wrapped in `PromiseLike`.
Use-cases:
- A function accepts a callback that may either return a value synchronously or may return a promised value.
- This type could be the return type of `Promise#then()`, `Promise#catch()`, and `Promise#finally()` callbacks.
Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/31394) if you want to have this type as a built-in in TypeScript.
@example
```
import type {Promisable} from 'type-fest';
async function logger(getLogEntry: () => Promisable<string>): Promise<void> {
const entry = await getLogEntry();
console.log(entry);
}
await logger(() => 'foo');
await logger(() => Promise.resolve('bar'));
```
@category Async
*/
Rule catalog ID: R054