Functional
Functional-programming policy rules from eslint-plugin-functional. They push code toward immutability, side-effect-free expressions, and expression-style control flow.
Most rules are useful in pieces. Projects rarely enable the whole family at "error". Enabling the whole set together expresses a strict functional-core / imperative-shell discipline.
Source: eslint-plugin-functional (MIT).
Rule index
Each rule name links to the detailed section below.
Examples come from the checked lint corpus or package-level rule tests when project layout matters.
functional/functional-parameters: Enforce functional parameter style: rejectarguments, reject rest parameters.functional/immutable-data: Reject property assignment , element assignment , andMap/Setmutation methods.functional/no-class-inheritance: Rejectabstractclasses andextendsclauses on class declarations.functional/no-classes: Rejectclassdeclarations and class expressions altogether.functional/no-conditional-statements: Rejectifandswitchstatements.functional/no-expression-statements: Reject expression statements that exist purely for their side effects.functional/no-let: Rejectletdeclarations so every binding isconst.functional/no-loop-statements: Rejectfor,while, anddo/whileloop statements.functional/no-mixed-types: Reject interfaces and type literals.functional/no-promise-reject: Reject any call toPromise.reject(...); resolve with anOption/Resultshape.functional/no-return-void: Reject void returns and functions whose declared return type isvoid.functional/no-this-expressions: Reject anythisexpression.functional/no-throw-statements: Rejectthrowstatements; functional code surfaces failures through return values instead.functional/no-try-statements: Rejecttry/catchandtry/finallystatements as a corollary offunctional/no-throw-statements.functional/prefer-immutable-types: Require declared variable, parameter, and property types.functional/prefer-property-signatures: Prefer function-property signatures over method shorthand in interfaces and type literals.functional/prefer-readonly-type: Preferreadonlyarray, tuple, collection, and property types over their mutable counterparts.functional/prefer-tacit: Reject trivial wrappers such asx => f(x).functional/readonly-type: Enforce one consistent spelling for readonly types,readonly T[]vsReadonlyArray<T>, across the project.functional/type-declaration-immutability: Enforce readonly/immutable type declarations by declaration name policy, for projects.
Configuration example
// lint.config.ts
import type { ITtscLintConfig } from "@ttsc/lint";
export default {
rules: {
"functional/no-let": "error",
"functional/no-loop-statements": "error",
"functional/no-conditional-statements": "error",
"functional/no-throw-statements": "error",
"functional/no-try-statements": "error",
"functional/no-classes": "error",
"functional/immutable-data": "error",
"functional/prefer-readonly-type": "error",
"functional/type-declaration-immutability": [
"error",
{
rules: [{ identifiers: ".*" }],
},
],
},
} satisfies ITtscLintConfig;Rules
functional/functional-parameters
Enforce functional parameter style: reject arguments, reject rest parameters, and optionally enforce a per-function parameter-count policy.
Options:
-
allowRestParameter?: booleanAllow rest parameters such as
(...args: readonly string[]). -
allowArgumentsKeyword?: booleanAllow the legacy
argumentsobject. -
enforceParameterCount?: boolean | "atLeastOne" | "exactlyOne"Require functions to declare parameters.
truemaps to the conservative at-least-one policy.
Example:
// reports: functional/functional-parameters (error)
function variadic(...args: number[]): number {
return args.length;
}functional/immutable-data
Reject property assignment (obj.x = ...), element assignment (arr[0] = ...), and Map/Set mutation methods. Configurable to allow mutation inside constructors or initialization expressions.
Options:
-
ignoreMapsAndSets?: booleanSkip mutating
MapandSetmethods while still checking arrays and property assignment.
Example:
const obj = { value: 1 };
// reports: functional/immutable-data (error)
obj.value = 2;functional/no-class-inheritance
Reject abstract classes and extends clauses on class declarations; prefer composition and structural typing.
Example:
class Base {}
// reports: functional/no-class-inheritance (error)
class Derived extends Base {}functional/no-classes
Reject class declarations and class expressions altogether.
Example:
// reports: functional/no-classes (error)
class Container {
value = 1;
}functional/no-conditional-statements
Reject if and switch statements. The conditional-expression forms (ternary, &&, ||) remain allowed.
Options:
-
allowReturningBranches?: boolean | "ifExhaustive"Reserved for upstream-compatible configs; the current native rule rejects all
if/switchstatements regardless of value.
Example:
const flag = true;
// reports: functional/no-conditional-statements (error)
if (flag) {
}functional/no-expression-statements
Reject expression statements that exist purely for their side effects (mutate(x);); pure code is built up from expressions with assigned or returned results.
Example:
// reports: functional/no-expression-statements (error)
console.log("saved");functional/no-let
Reject let declarations so every binding is const. The shared ignore-pattern options can carve out specific identifier shapes (test locals, loop counters) when a full ban is too aggressive.
Options:
-
allowInForLoopInit?: booleanPermit
letin aforstatement initializer. -
allowInFunctions?: booleanPermit
letinside functions while still rejecting module-levellet.
Example:
// reports: functional/no-let (error)
let count = 0;functional/no-loop-statements
Reject for, while, and do/while loop statements; use recursive helpers or array methods (map, reduce) instead.
Example:
const items = [1, 2, 3];
// reports: functional/no-loop-statements (error)
for (const item of items) {
}functional/no-mixed-types
Reject interfaces and type literals that mix property, method, call, and index member kinds; mixed shapes make composition harder.
Options:
-
checkInterfaces?: booleanCheck interface member kinds.
-
checkTypeLiterals?: booleanCheck type-literal member kinds.
Example:
type Mixed = {
value: number;
// reports: functional/no-mixed-types (error)
compute(): number;
};functional/no-promise-reject
Reject any call to Promise.reject(...); resolve with an Option / Result shape so failures stay in the value channel.
Example:
// reports: functional/no-promise-reject (error)
const rejection = Promise.reject(new Error("nope"));functional/no-return-void
Reject void returns and functions whose declared return type is void; functions should always return a value.
Options:
-
allowNull?: booleanPermit a function that returns
nullto satisfy the rule. -
allowUndefined?: booleanPermit a function that returns
undefinedto satisfy the rule. -
ignoreInferredTypes?: booleanSkip functions whose return type is inferred to be
voidrather than declared explicitly.
Example:
// reports: functional/no-return-void (error)
function log(): void {
// reports: functional/no-return-void (error)
return;
}functional/no-this-expressions
Reject any this expression. Combined with functional/no-classes this leaves no place where this is legal; on its own it still forbids this in standalone functions, modules, and arrow pipelines.
Example:
const value: unknown = "current";
function read(this: { value: unknown }) {
// reports: functional/no-this-expressions (error)
return this.value;
}functional/no-throw-statements
Reject throw statements; functional code surfaces failures through return values (Either, Result) instead.
Options:
-
allowToRejectPromises?: booleanReserved for upstream-compatible configs; the current native rule rejects every
throwstatement regardless of value.
Example:
function boom(): never {
// reports: functional/no-throw-statements (error)
throw new Error("boom");
}functional/no-try-statements
Reject try/catch and try/finally statements as a corollary of functional/no-throw-statements.
Options:
-
allowCatch?: booleanAllow
try/catchwhile still checkingfinallywhen present. -
allowFinally?: booleanAllow
try/finallywhile still checkingcatchwhen present.
Example:
function run(): void {}
function recover(error: unknown): void {
console.error(error);
}
// reports: functional/no-try-statements (error)
try {
run();
} catch (error) {
recover(error);
}functional/prefer-immutable-types
Require declared variable, parameter, and property types to be readonly or otherwise structurally immutable.
Options:
-
enforcement?: | "ReadonlyShallow" | "ReadonlyDeep" | "Immutable" | "None" | falseMinimum accepted immutability. The native subset treats any configured value as readonly-required.
Example:
// reports: functional/prefer-immutable-types (error)
const values: string[] = [];functional/prefer-property-signatures
Prefer function-property signatures (fn: () => T) over method shorthand (fn(): T) in interfaces and type literals.
Only the property form accepts readonly, so method shorthand silently makes the slot mutable; overloads still need the method form.
Example:
interface Api {
// reports: functional/prefer-property-signatures (error)
run(): void;
}functional/prefer-readonly-type
Prefer readonly array, tuple, collection, and property types over their mutable counterparts.
Options:
-
allowLocalMutation?: booleanPermit mutation of locals while still policing exported types.
-
allowMutableReturnType?: booleanPermit a mutable return type even when parameters must be readonly.
-
checkImplicit?: booleanAlso check property positions that have no explicit type annotation.
-
ignoreCollections?: booleanSkip array / tuple /
Map/Settypes. -
ignoreClass?: boolean | "fieldsOnly"Skip class fields.
"fieldsOnly"keeps the rule active for non-field class members. -
ignoreInterface?: booleanSkip interface members entirely.
Example:
// reports: functional/prefer-readonly-type (error)
type Values = string[];functional/prefer-tacit
Reject trivial wrappers such as x => f(x) in favor of the tacit form f; reduces noise in functional pipelines.
Options:
-
checkMemberExpressions?: booleanCheck member expressions such as
x => service.map(x).
Example:
function transform(value: number): number {
return value * 2;
}
// reports: functional/prefer-tacit (error)
const map = (value: number) => transform(value);functional/readonly-type
Enforce one consistent spelling for readonly types, readonly T[] vs ReadonlyArray<T>, across the project.
Options:
-
prefer?: "keyword" | "generic"Preferred readonly spelling. Default:
"keyword".
Example:
// reports: functional/readonly-type (error)
type Values = ReadonlyArray<string>;functional/type-declaration-immutability
Enforce readonly/immutable type declarations by declaration name policy, for projects that want only types matching certain naming conventions to be locked down.
Options:
-
rules?: readonly ITtscLintFunctionalTypeDeclarationImmutabilityRule[]Declaration-name policies. Empty means all type declarations.
-
ignoreInterfaces?: booleanSkip interface declarations and only check type aliases.
Example:
// reports: functional/type-declaration-immutability (error)
interface State {
values: string[];
}