@ codeforbreakfast/ slint 无效
ESLint规则和配置用于执行功能编程最佳做法和平庸效应代码模式的Effect项目.
安装
npm install --save-dev @codeforbreakfast/eslint-effect
# or
bun add --dev @codeforbreakfast/eslint-effect
特征
本套件提供:
- 自定义 ESLint 规则 特定效果模式
- 语法限制 执行职能方案拟订原则
- 预设规则集 不同背景
- 功能不可变规则 适应效果类型
自定义规则
no-unnecessary-pipe-wrapper
在单管操作周围检测到不必要的功能包接.
恶:
import { pipe } from 'effect';
declare const transform: (x: unknown) => unknown;
const fn = (x: unknown) => pipe(x, transform);
不错:
declare const transform: (x: unknown) => unknown;
const fn = transform;
no-eta-expansion
检测到不必要的函数包(eta-expansion),它只将参数直接传递到另一个函数. 也被称为"更优先的无分地风格"
恶:
import { Console } from 'effect';
declare const doSomething: (x: number) => unknown;
declare const processData: (a: string, b: number) => unknown;
const logError = (msg: string) => Console.error(msg);
const transform = (x: number) => doSomething(x);
const handler = (a: string, b: number) => processData(a, b);
不错:
import { Console } from 'effect';
declare const doSomething: (x: number) => unknown;
declare const processData: (a: string, b: number) => unknown;
const logError = Console.error;
const transform = doSomething;
const handler = processData;
理由:在功能编程中,去除(Xx.f(x) f)消除了不必要的间接. 当一个函数仅直接传递其参数给另一个函数而没有任何变换时,包裹会不增加值并降低可读性.
no-unnecessary-function-alias
检测到不必要功能别名, 不提供语义值 。 当一个常数被直接指派到另一个函数而不增加清晰度或抽象度时,应当在调用站点被内置.
恶:
import { Array, Ref } from 'effect';
declare const ref: Ref.Ref<unknown>;
declare const arr: readonly unknown[];
declare function useOnce(val: unknown): void;
declare function useTwice(val: unknown): void;
const getState = Ref.get;
const transform = Array.map;
// Used only once or twice
useOnce(getState(ref));
useTwice(transform(arr, (x: unknown) => (x as number) * 2));
不错:
import { Array, Ref, Stream } from 'effect';
declare const ref: Ref.Ref<unknown>;
declare const arr: readonly unknown[];
declare function useOnce(val: unknown): void;
declare function useTwice(val: unknown): void;
// Inline when used infrequently
useOnce(Ref.get(ref));
useTwice(Array.map(arr, (x: unknown) => (x as number) * 2));
// OR keep the alias if it adds semantic value
// eslint-disable-next-line effect/no-unnecessary-function-alias -- Alias clarifies stream processing context
const collectStreamResults = Stream.runCollect;
配置 :
maxReferences(默认 :2- 在别名被认为有正当理由之前最多参考次数
{
rules: {
'effect/no-unnecessary-function-alias': ['warn', {
maxReferences: 3, // Allow aliases used 3+ times
}]
}
}
理由: 仅使用一次或两次的函数别名会增加认知间接费用而无有意义的好处. 它们迫使读者从别名定义到使用网站之间跳出. 直接函数调用更直接. 然而,经常使用(3+次)或通过名称来增加语义清晰度的别名应当保留.
prefer-match-tag
强制执行 Match.tag() 结束 Match.when() 页:1 _tag 歧视者.
恶:
import { Match, pipe } from 'effect';
type Tagged = { _tag: 'Success' } | { _tag: 'Error' };
declare const value: Tagged;
declare const handler: (val: { _tag: 'Success' }) => unknown;
pipe(Match.value(value), Match.when({ _tag: 'Success' }, handler));
不错:
import { Match, pipe } from 'effect';
type Tagged = { _tag: 'Success' } | { _tag: 'Error' };
declare const value: Tagged;
declare const handler: (val: { _tag: 'Success' }) => unknown;
pipe(Match.value(value), Match.tag('Success', handler));
prefer-match-over-conditionals
鼓励声明 Match 模式相对于必要 if 效果回调中的语句.
恶:
import { Effect, Match, pipe } from 'effect';
type TaggedValue = { _tag: 'Success' } | { _tag: 'Error' };
declare const handleSuccess: (x: { _tag: 'Success' }) => Effect.Effect<unknown>;
declare const handleError: (x: TaggedValue) => Effect.Effect<unknown>;
declare const effectValue: Effect.Effect<TaggedValue>;
pipe(
effectValue,
Effect.flatMap((x: TaggedValue) => {
if (x._tag === 'Success') return handleSuccess(x);
return handleError(x);
})
);
不错:
import { Effect, Match, pipe } from 'effect';
type TaggedValue = { _tag: 'Success' } | { _tag: 'Error' };
declare const handleSuccess: (x: { _tag: 'Success' }) => Effect.Effect<unknown>;
declare const handleError: (x: TaggedValue) => Effect.Effect<unknown>;
declare const effectValue: Effect.Effect<TaggedValue>;
pipe(
effectValue,
Effect.flatMap((x: TaggedValue) =>
pipe(Match.value(x), Match.tag('Success', handleSuccess), Match.orElse(handleError))
)
);
prefer-effect-if-over-match-boolean
强制执行 Effect.if 结束 Match.value 对于布尔条件. Match.value 应保留在多个值上进行模式匹配,而非简单的真/假分支.
恶:
import { Effect, Match, pipe } from 'effect';
declare const isValid: boolean;
declare const user: { isAdmin: boolean };
declare function grantAccess(): Effect.Effect<unknown>;
declare function denyAccess(): Effect.Effect<unknown>;
pipe(
isValid,
Match.value,
Match.when(true, () => Effect.succeed('valid')),
Match.when(false, () => Effect.fail('invalid')),
Match.exhaustive
);
pipe(
user.isAdmin,
Match.value,
Match.when(true, () => grantAccess()),
Match.when(false, () => denyAccess()),
Match.exhaustive
);
不错:
import { Effect } from 'effect';
declare const isValid: boolean;
declare const user: { isAdmin: boolean };
declare function grantAccess(): Effect.Effect<unknown>;
declare function denyAccess(): Effect.Effect<unknown>;
Effect.if(isValid, {
onTrue: () => Effect.succeed('valid'),
onFalse: () => Effect.fail('invalid'),
});
Effect.if(user.isAdmin, {
onTrue: () => grantAccess(),
onFalse: () => denyAccess(),
});
理由数字 : Match.value 旨在对受歧视的工会和多种价值观进行模式匹配。 用它来做简单的布尔条件 是动词和模糊的意图. Effect.if 明确、简洁和清晰地传达布尔分支逻辑.
prefer-match-over-ternary
鼓励声明 Match.value 当模式匹配非布尔值时,或者在函数调用之间选择时,模式会超越三位运算符.
说明: 对于布尔条件返回效果,使用 Effect.if 相反(见 prefer-effect-if-over-match-boolean (见上文规则).
恶:
import { Option, Stream } from 'effect';
type FilterFn = (v: unknown) => boolean;
declare const filter: FilterFn | undefined;
declare const stream: Stream.Stream<unknown>;
declare function processValue(val: number): unknown;
declare function getDefault(): unknown;
declare function finalizeTask(): unknown;
declare function continueTask(): unknown;
const result = filter !== undefined ? Stream.filter(stream, filter) : stream;
const handler = (option: Option.Option<number>) =>
Option.isSome(option) ? processValue(option.value) : getDefault();
const processStatus = (status: 'pending' | 'active' | 'complete') =>
status === 'complete' ? finalizeTask() : continueTask();
不错:
import { Match, Option, pipe, Stream } from 'effect';
type FilterFn = (v: unknown) => boolean;
declare const filter: FilterFn | undefined;
declare const stream: Stream.Stream<unknown>;
declare function processValue(val: number): unknown;
declare function getDefault(): unknown;
declare function finalizeTask(): unknown;
declare function continueTask(): unknown;
const result = pipe(
filter,
Match.value,
Match.when(Match.undefined, () => stream),
Match.orElse((f) => Stream.filter(stream, f))
);
const handler = (option: Option.Option<number>) =>
pipe(
option,
Match.value,
Match.when({ _tag: 'Some' }, (opt) => processValue(opt.value)),
Match.orElse(getDefault)
);
const processStatus = (status: 'pending' | 'active' | 'complete') =>
pipe(status, Match.value, Match.when('complete', finalizeTask), Match.orElse(continueTask));
对于带效果的布尔条件,使用 Effect.if数字 :
import { Effect } from 'effect';
declare const condition: boolean;
// Boolean condition returning Effects - use Effect.if, NOT Match.value
const result = Effect.if(condition, {
onTrue: () => Effect.succeed(42),
onFalse: () => Effect.fail('error'),
});
理由: 三级操作员是必须的,而且比 Match 模式。 使用 Match.value 为可选类型、联盟类型或非布尔条件等值的图案匹配提供了更好的可比较性。 但是,对于简单的布尔条件 返回效果, Effect.if 因为它更清晰 更安全 纯值之三(不是函数调用)是允许的,因为它们适合简单的值选择.
no-switch-statement
功能效应代码中的禁用交换语句. 切换语句是必须的,不提供详尽无遗的检查. 使用 Match 用于类型安全、详尽无遗的模式匹配.
恶:
import { Match, pipe } from 'effect';
type Event = { type: 'Created' } | { type: 'Updated' } | { type: 'Other' };
declare const event: Event;
declare function handleCreated(e: Event): unknown;
declare function handleUpdated(e: Event): unknown;
declare function handleUnknown(e: Event): unknown;
function processEvent() {
switch (event.type) {
case 'Created':
return handleCreated(event);
case 'Updated':
return handleUpdated(event);
default:
return handleUnknown(event);
}
}
不错:
import { Match, pipe } from 'effect';
type Event = { type: 'Created' } | { type: 'Updated' } | { type: 'Other' };
declare const event: Event;
declare function handleCreated(e: Event): unknown;
declare function handleUpdated(e: Event): unknown;
declare function handleUnknown(e: Event): unknown;
pipe(
Match.value(event),
Match.when({ type: 'Created' }, handleCreated),
Match.when({ type: 'Updated' }, handleUpdated),
Match.orElse(handleUnknown)
);
受歧视的工会 _tag数字 :
import { Match, pipe } from 'effect';
type TaggedEither = { _tag: 'Right'; value: unknown } | { _tag: 'Left'; error: unknown };
declare const either: TaggedEither;
declare function handleRight(val: { _tag: 'Right'; value: unknown }): unknown;
declare function handleLeft(val: { _tag: 'Left'; error: unknown }): unknown;
pipe(
Match.value(either),
Match.tag('Right', handleRight),
Match.tag('Left', handleLeft),
Match.exhaustive
);
no-if-statement
如果功能效应代码中的语句, 则禁止此语句 。 如果声明是必须的 并且没有很好的构思。 使用 Effect.if 对有效果的布尔条件, Match.value 用于图案匹配,或用于声明控制流的特定类型匹配器.
恶:
import { Effect, Option, pipe } from 'effect';
declare const todoState: { deleted: boolean };
declare const event: { type: string; data: { title: string } };
declare const option: Option.Option<string>;
declare const state: Option.Option<{ deleted: boolean }>;
declare const defaultValue: string;
// Bad pattern 1
function check1() {
if (todoState.deleted) {
return Effect.fail(new Error('Cannot complete deleted TODO'));
}
return Effect.succeed(todoState);
}
// Bad pattern 2
function check2() {
if (event.type === 'TodoCreated') {
return Effect.succeed({ title: event.data.title, completed: false });
}
return pipe(state, Option.match({ onNone: () => defaultValue, onSome: (s) => s }));
}
// Bad pattern 3
function check3() {
if (Option.isSome(option)) {
return option.value;
}
return defaultValue;
}
不错:
import { Effect, Option, Match, pipe } from 'effect';
declare const todoState: { deleted: boolean };
declare const event: { type: string; data: { title: string } };
declare const option: Option.Option<string>;
declare const state: Option.Option<{ deleted: boolean }>;
declare const defaultValue: string;
declare const condition: boolean;
// Boolean conditionals with Effects
Effect.if(todoState.deleted, {
onTrue: () => Effect.fail(new Error('Cannot complete deleted TODO')),
onFalse: () => Effect.succeed(todoState),
});
// Pattern matching on discriminated unions
pipe(
event,
Match.value,
Match.when({ type: 'TodoCreated' }, (e) =>
Effect.succeed({ title: e.data.title, completed: false })
),
Match.orElse((e) => pipe(state, Option.match({ onNone: () => defaultValue, onSome: (s) => s })))
);
// Option/Either with built-in matchers
pipe(
option,
Option.getOrElse(() => defaultValue)
);
// Simple value selection - use ternary operators
const x = condition ? 'yes' : 'no';
理由:如果语句打破了功能构成,使代码更难解释. 它们没有提供图案匹配的详尽无遗的检查,而且不能轻易地由管子组成. 使用 Effect.if, (中文(简体) ), Match.value,或者特定类型匹配者喜欢 Option.match 提供更好的类型安全、详尽无遗的检查和可容性。 初等运算符仍然被允许进行简单的值选择,因为它们适合纯值.
prefer-schema-validation-over-assertions
Effect recalls中的不鼓励类型断言有利于运行时间验证.
恶:
import { Effect } from 'effect';
type MyType = { value: string };
declare function handler(x: MyType): unknown;
Effect.map((x: unknown) => handler(x as MyType));
不错:
import { Effect, pipe, Schema } from 'effect';
type MyType = { value: string };
declare const MyTypeSchema: Schema.Schema<MyType>;
declare const input: Effect.Effect<unknown>;
declare function handler(x: MyType): unknown;
pipe(input, Effect.flatMap(Schema.decodeUnknown(MyTypeSchema)), Effect.map(handler));
suggest-currying-opportunity
建议 curry 用户定义的功能去除管链中的箭头功能包. 默认情况下,仅在参数已经处于正确顺序(不需要重新排序)时才会建议咖喱,并且限制单级咖喱的可读性.
QQ 将建议( 好模式 - 已到尾端的参数 ) :
import { Effect } from 'effect';
declare const myEffect: Effect.Effect<unknown>;
declare function logError(message: string, error: unknown): Effect.Effect<void>;
// Before
Effect.catchAll(myEffect, (error) => logError('Failed', error));
// After currying (params already in right order)
const logErrorCurried = (message: string) => (error: unknown) =>
Effect.sync(() => console.error(message, error));
Effect.catchAll(myEffect, logErrorCurried('Failed'));
QQ 不通过默认建议( 需要参数重排) :
import { Effect } from 'effect';
declare const myEffect: Effect.Effect<unknown>;
declare function logError(error: unknown, message: string): Effect.Effect<void>;
// This would break semantic order - error should come before message
Effect.catchAll(myEffect, (error) => logError(error, 'Failed'));
// Would require changing to: logError = (message) => (error) => ...
// But semantically, error should come first in the return object
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}不会以默认的方式提出 {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}会创造出深层的咖喱声:
import { Effect } from 'effect';
declare const myEffect: Effect.Effect<unknown>;
declare function processData(prefix: string, suffix: string, data: unknown): unknown;
// Would create 2-level currying: (prefix) => (suffix) => (data) => ...
Effect.map(myEffect, (data) => processData('prefix', 'suffix', data));
// Too many parentheses at call site: processData('prefix')('suffix')
配置选项 :
allowReordering(默认 :false- 即使参数需要重新排序,也允许提出建议maxCurriedParams(默认 :1,最大值 :3) - 可建议的最大曲尾参数数
{
rules: {
'effect/suggest-currying-opportunity': ['warn', {
allowReordering: true, // Allow parameter reordering suggestions
maxCurriedParams: 2, // Allow up to 2-level currying
}]
}
}
说明: 此规则只触发用户定义的函数,而不是效果库函数.
no-intermediate-effect-variables
被禁者存储 Effect/Stream/pipe,当它们被内接入管链时会产生中间变量. 允许配置数据,如调度常数、重试政策和作为参数通过的效果值.
坏( 应当内含) :
import { Effect, pipe, Schema } from 'effect';
type User = { id: string; name: string };
declare const userId: string;
declare const UserSchema: Schema.Schema<User>;
declare const data: unknown;
declare function fetchUser(id: string): Effect.Effect<User>;
declare function validateUser(u: User): Effect.Effect<User>;
declare function formatUserData(u: User): unknown;
declare function processUser(u: User): User;
declare function saveToDatabase(u: User): Effect.Effect<void>;
// Breaking up the pipe chain for a single use
const userEffect = fetchUser(userId);
const result = pipe(userEffect, Effect.flatMap(validateUser), Effect.map(formatUserData));
// Storing intermediate pipe results used once
function processData() {
const validated = pipe(data, Schema.decodeUnknown(UserSchema));
const processed = Effect.map(validated, processUser);
return Effect.flatMap(processed, saveToDatabase);
}
// Schema defined but only used once
const UserIdSchema = pipe(Schema.String, Schema.nonEmptyString());
export const decodeUserId = Schema.decode(UserIdSchema); // Only usage
好( 内置管道值) :
import { Effect, pipe, Schema } from 'effect';
type User = { id: string; name: string };
declare const userId: string;
declare const UserSchema: Schema.Schema<User>;
declare const data: unknown;
declare function fetchUser(id: string): Effect.Effect<User>;
declare function validateUser(u: User): Effect.Effect<User>;
declare function formatUserData(u: User): unknown;
declare function processUser(u: User): User;
declare function saveToDatabase(u: User): Effect.Effect<void>;
// Single cohesive pipe chain
const result = pipe(fetchUser(userId), Effect.flatMap(validateUser), Effect.map(formatUserData));
// All transformations in one composition
function processData() {
return pipe(
data,
Schema.decodeUnknown(UserSchema),
Effect.map(processUser),
Effect.flatMap(saveToDatabase)
);
}
// Schema inlined directly
export const decodeUserId = Schema.decode(pipe(Schema.String, Schema.nonEmptyString()));
好(配置数据):
import { Effect, pipe, Schedule } from 'effect';
declare const operation: Effect.Effect<unknown>;
// Schedule constants used as configuration
const retrySchedule = pipe(
Schedule.exponential('100 millis'),
Schedule.union(Schedule.spaced('1 second'))
);
const result = pipe(operation, Effect.retry(retrySchedule));
// Effect values used as parameters
const defaultValue = Effect.succeed(42);
const combined = pipe(
Effect.succeed(1),
Effect.zipWith(defaultValue, (a, b) => a + b)
);
好(多种用途 -- -- 合法再利用):
import { Context, Effect, Layer, pipe } from 'effect';
declare class PgClientService extends Context.Tag('PgClient')<PgClientService, unknown>() {}
declare const createPgClient: Effect.Effect<unknown>;
declare const Migration: { layer: Layer.Layer<unknown> };
declare const EventStore: { layer: Layer.Layer<unknown> };
declare function it(name: string, fn: () => unknown): void;
// Layer reused in multiple compositions
const PgLive = Layer.effect(PgClientService, createPgClient);
const Layer1 = pipe(Migration.layer, Layer.provide(PgLive)); // Use 1
const Layer2 = pipe(EventStore.layer, Layer.provide(PgLive)); // Use 2
// Effect reused across test cases
const setupTest = Effect.gen(function* () {
yield* Effect.void;
});
it('test 1', () =>
pipe(
setupTest,
Effect.flatMap(() => Effect.void)
)); // Use 1
it('test 2', () =>
pipe(
setupTest,
Effect.flatMap(() => Effect.void)
)); // Use 2
好( 执行结果为纯值 ) :
import { Effect, Either, pipe } from 'effect';
type Request = { token: string };
declare const req: Request;
declare function authenticate(r: Request): Effect.Effect<string, Error>;
// runSync returns a plain value, not an Effect
function handleAuth() {
const authResult = Effect.runSync(pipe(authenticate(req), Effect.either));
if (Either.isLeft(authResult)) {
return { json: () => ({ error: authResult.left }) };
}
return { json: () => ({ token: authResult.right }) };
}
理由: 中间管线变量会断流管组成. 诸如作为Effect 操作参数的调度常数和效应值等配置数据是合法的组成部分,应当提取. 多种用途也证明可变提取是合理的.
说明: 这是一条侵略性规则,包含在 pipeStrict 相会.
规则预设
建议的预设
recommended ⭐
建议用于大多数项目 - 核心效果最佳做法,没有有争议的规则:
- 所有效果插件规则
- 禁止类(效果标记/错误除外)
- 无效
Effect.runSync编号 :runPromise生产 - 强制执行
Effect.andThen()结束Effect.flatMap(() => ) - 强制执行
Effect.as()结束Effect.map(() => value) - 基于禁药方法
.pipe()(单独使用)pipe()(中文(简体) ) - 禁止 curried 函数调用( 使用)
pipe改为) - 在转换中禁止身份功能
- 执行适当的管道参数命令
不包括:
Effect.gen禁用( 选择使用noGen(中文(简体) )_tag访问禁入( 选择 )preferMatch(中文(简体) )- 严格的管线规则(可选入)
pipeStrict(中文(简体) )
strict
对于狂热者 - 所有东西 recommended 加上所有有意见的规则:
- 全体
recommended规则 - 无效
Effect.gen(使用时pipe改为) - 直接禁止
_tag访问(使用类型守护或Match(中文(简体) ) - 全部禁止
switch语句( 使用Match.value用于图案匹配) - 全部禁止
if语句( 使用Effect.if, (中文(简体) ),Match.value,或类型特定匹配者) - 禁忌筑巢
pipe()电话 - 禁止多个
pipe()在一个函数中呼叫
选入配置
把这些和 recommended 要定制您的规则 :
noGen
无效 Effect.gen 赞成: pipe 组成. 有争议 - 有些球队更喜欢金!
preferMatch
直接禁止 _tag 访问, 全部 switch 发言,以及所有发言 if 发言。 鼓励声明 Match 模式, Effect.if 用于布尔条件和特定类型匹配者.
pipeStrict
执行严格的管材构成规则:
- 禁忌筑巢
pipe()电话 - 禁止多个
pipe()每个函数的呼叫 - 禁止将管道/效果储存在单一用途中间变量中
plugin
插件规则, 没有语法限制 .
功能可变性
functionalImmutabilityRules
积分 eslint-plugin-functional 带有效果感知配置 :
- 执行只读类型,但效果类型除外
- 无效
let约束 - 执行不可改变的数据模式
- 禁用循环( 使用)
Effect.forEach, (中文(简体) ),Array.map页:1
使用量
建议设置
开始 recommended 对于合理的默认 :
import effectPlugin from '@codeforbreakfast/eslint-effect';
export default [
{
...effectPlugin.configs.recommended,
files: ['**/*.ts', '**/*.tsx'],
plugins: {
effect: effectPlugin,
},
},
];
添加意见规则
必要时选择采用更严格的规则:
import effectPlugin from '@codeforbreakfast/eslint-effect';
export default [
{
...effectPlugin.configs.recommended,
files: ['**/*.ts', '**/*.tsx'],
plugins: {
effect: effectPlugin,
},
},
// Forbid Effect.gen
{
...effectPlugin.configs.noGen,
files: ['src/**/*.ts'],
},
// Enforce strict pipe rules
{
...effectPlugin.configs.pipeStrict,
files: ['src/**/*.ts'],
},
// Or just use strict for everything
{
...effectPlugin.configs.strict,
files: ['src/**/*.ts'],
plugins: {
effect: effectPlugin,
},
},
];
有功能可变性
要求数 eslint-plugin-functional数字 :
import functionalPlugin from 'eslint-plugin-functional';
import effectPlugin from '@codeforbreakfast/eslint-effect';
export default [
{
files: ['**/*.ts'],
plugins: {
functional: functionalPlugin,
},
rules: effectPlugin.configs.functionalImmutabilityRules,
},
{
...effectPlugin.configs.recommended,
files: ['**/*.ts'],
plugins: {
effect: effectPlugin,
},
},
];
禁用个别规则
所有语法限制规则都作为命名为ESLint的规则被曝光,从而容易禁用特定规则:
import effectPlugin from '@codeforbreakfast/eslint-effect';
export default [
{
...effectPlugin.configs.recommended,
files: ['scripts/**/*.ts'],
plugins: {
effect: effectPlugin,
},
rules: {
// Allow runPromise/runSync in scripts (application entry points)
'effect/no-runPromise': 'off',
'effect/no-runSync': 'off',
},
},
];
可用的命名规则 :
effect/no-classes- 无效类别,但效果标记/错误除外effect/no-runSync- 无效效应. runSynceffect/no-runPromise- 无效效果. 运行保证effect/prefer-andThen- 使用然后在平面图上使用(( ())...)effect/prefer-as- 使用超度地图( () QQ值)effect/no-gen- 强制效应.gen(通过noGen配置( c)effect/no-unnecessary-pipe-wrapper- 检测不必要的管子包装器effect/no-eta-expansion- 检测不必要的函数包装( 偏好无点样式)effect/no-unnecessary-function-alias- 检测不必要的函数别名effect/prefer-match-tag- 使用 Match.tag 代替 Match. when for tageffect/prefer-match-over-conditionals- 如果声明使用匹配effect/prefer-effect-if-over-match-boolean- 对布尔条件使用Effect.如果超过Match.值effect/prefer-match-over-ternary- 使用 Match. value 超过三元运算符进行非布尔模式匹配effect/no-switch-statement- 禁止所有开关语句(使用Match.value代替)effect/no-if-statement- 如果语句(使用Effect.if、Match.value或类型特定匹配者代替),则全部禁止effect/prefer-schema-validation-over-assertions- 使用Schema来代替类型断言effect/suggest-currying-opportunity- 建议咖喱去除箭头功能包effect/no-intermediate-effect-variables- 禁止储存管/影响结果,产生单用中间变量(通过pipeStrict配置( c)
可用出口
默认导出( 建议)
// @ts-nocheck - Package types available at runtime
import effectPlugin from '@codeforbreakfast/eslint-effect';
effectPlugin.rules; // All custom rules
effectPlugin.meta; // Plugin metadata
// Configs
effectPlugin.configs.recommended; // ⭐ Recommended for most projects
effectPlugin.configs.strict; // All rules including opinionated ones
effectPlugin.configs.noGen; // Opt-in: forbid Effect.gen
effectPlugin.configs.preferMatch; // Opt-in: forbid _tag access
effectPlugin.configs.pipeStrict; // Opt-in: strict pipe rules
effectPlugin.configs.plugin; // Plugin rules only
effectPlugin.configs.functionalImmutabilityRules; // Functional immutability rules object
每个配置( 除 functionalImmutabilityRules)是一个完整的ESLint平面配置对象,有:
name: 配置标识符rules: 规则配置plugins: 需要的插件(如适用)
已命名的出口
// @ts-nocheck - Package types available at runtime
import {
rules, // All custom rules (for plugin registration)
functionalImmutabilityRules, // Functional immutability rules object
} from '@codeforbreakfast/eslint-effect';
范围导入
import rules from '@codeforbreakfast/eslint-effect/rules';
哲学
这个软件包执行严格的功能编程风格,并带有效果:
- 代际组成页:1
pipe组成情况Effect.gen - 类型安全: 使用运行时间验证(Schema)而不是类型断言
- 声明模式: 使用
Match超过必要条件 - 可变性: 执行只读类型和永久数据模式
- 边界执行: 只在应用程序边界运行效果
许可证
麻省理工学院