Строгие семантические соглашения, предназначенные для устранения двусмысленности и технического долга через статический анализ.
Преимущества: Единообразие имен упрощает навигацию, а автоматические проверки линтера предотвращают накопление архитектурного долга.
Повсеместно используется kebab-case, включая хуки (use-auth.ts, сама функция — useAuth). Исключения: служебные файлы (формат entity.type.ts) и стандартные файлы Next.js.
1// kebab-case и семантические расширения
2src/entities/tour/schema/finance-info.schema.ts
3src/entities/tour/api/tour.service.ts
4src/entities/tour/converters/tour.converters.ts
5src/entities/tour/handlers/tour.handlers.ts
6src/entities/tour/mock/tour-finance.mock.ts
7src/entities/tour/constants/tour-status.config.tsВключается через eslint-plugin-unicorn (unicorn/filename-case). Семантические суффиксы разрешены через ignore; хуки — обычный kebab-case (use-x.ts).
1// eslint.config.js — unicorn/filename-case
2"unicorn/filename-case": [
3 "error",
4 {
5 cases: {
6 kebabCase: true,
7 camelCase: false,
8 pascalCase: false
9 },
10 ignore: [
11 /^[a-z0-9-]+\.(service|api|util|config|types|interface|store|hook|slice|schema|converters|handlers|mock)\.ts$/,
12 /^[a-z0-9-]+\.(service|store|api|util|config|hook|slice)\.(types|interface)\.ts$/,
13 /^[a-z0-9-]+-backend\.interface\.ts$/,
14 /^(page|layout|loading|error|not-found|template|default)\.tsx?$/,
15 /^(globals|metadata)\.css$/,
16 /^\.[a-z][a-z0-9-]*rc(\.(js|ts|json))?$/,
17 /^i18n\.(init|blocks|checker)\.ts$/,
18 /^[a-z0-9-]+\.context\.ts$/
19 ]
20 }
21]
22Интерфейсы — префикс I, типы — префикс T, перечисления — префикс ENUM_. Компоненты — PascalCase.
1// Префиксы для типов и интерфейсов
2interface IEntity { ... }
3type TResponse = { ... }
4const ENUM_STATUS = { ... } as const;Гейт I* / T* / hooks через @typescript-eslint/naming-convention. Alias-типы ENUM_* исключены из правила префикса T*.
1// eslint.config.js — @typescript-eslint/naming-convention
2"@typescript-eslint/naming-convention": [
3 "error",
4 {
5 selector: "interface",
6 format: ["PascalCase"],
7 prefix: ["I"]
8 },
9 {
10 selector: "typeAlias",
11 format: ["PascalCase"],
12 filter: { regex: "^ENUM_[A-Z]", match: false },
13 prefix: ["T"]
14 },
15 {
16 selector: "variable",
17 modifiers: ["const", "exported"],
18 types: ["string", "number", "boolean"],
19 format: ["UPPER_CASE"]
20 },
21 {
22 selector: "function",
23 format: ["camelCase", "PascalCase"]
24 },
25 {
26 selector: "variable",
27 modifiers: ["const", "exported"],
28 filter: { regex: "^use[A-Z]", match: true },
29 format: ["camelCase"]
30 },
31 {
32 selector: "function",
33 filter: { regex: "^use[A-Z]", match: true },
34 format: ["camelCase"]
35 }
36]
37Классическая иерархия слоев: shared — самый нижний, app — самый верхний. Импорты 'снизу вверх' или между элементами одного слоя (кроме shared) строго запрещены.
1// FSD Import Boundaries (Classic)
2app -> [pages, widgets, features, entities, shared]
3pages -> [widgets, features, entities, shared]
4widgets -> [features, entities, shared]
5features -> [entities, shared]
6entities -> [shared]
7shared -> []ESLint overrides для vendor UI (shadcn-ui), деклараций типов (.d.ts) и конфигов, где строгий нейминг мешает toolchain.
1// eslint.config.js — overrides (vendor / generated / configs)
2{
3 files: [
4 "src/shared/ui/shadcn-ui/**/*.{ts,tsx}",
5 "src/shared/ui/custom/**/*.tsx"
6 ],
7 rules: {
8 "@typescript-eslint/naming-convention": "off",
9 "@typescript-eslint/no-explicit-any": "off"
10 }
11},
12{
13 files: ["**/*.d.ts"],
14 rules: { "@typescript-eslint/naming-convention": "off" }
15},
16{
17 files: ["**/*.config.{ts,js}", "vite.config.ts", "tailwind.config.ts"],
18 rules: {
19 "@typescript-eslint/no-require-imports": "off",
20 "no-console": "off"
21 }
22}
23