@ryuzaki13/react-foundation-lib 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +172 -114
- package/dist/chunks/{formatters-CBgrBeSA.js → formatters-D33Uh3si.js} +7 -8
- package/dist/chunks/{formatters-CBgrBeSA.js.map → formatters-D33Uh3si.js.map} +1 -1
- package/dist/chunks/odata-service-CWkHASdw.js +2211 -0
- package/dist/chunks/odata-service-CWkHASdw.js.map +1 -0
- package/dist/chunks/{validate-BW-7BZy_.js → validate-DyzojM0w.js} +2 -2
- package/dist/chunks/{validate-BW-7BZy_.js.map → validate-DyzojM0w.js.map} +1 -1
- package/dist/error-report/index.js +2 -2
- package/dist/excel/index.js +20 -21
- package/dist/excel/index.js.map +1 -1
- package/dist/formatters/index.js +4 -5
- package/dist/{odata → odata-service}/buildSeparatedArrays.d.ts +1 -1
- package/dist/odata-service/buildSeparatedArrays.d.ts.map +1 -0
- package/dist/{odata/types.d.ts → odata-service/collectionTypes.d.ts} +1 -1
- package/dist/odata-service/collectionTypes.d.ts.map +1 -0
- package/dist/{odata → odata-service}/dateUtils.d.ts +1 -1
- package/dist/odata-service/dateUtils.d.ts.map +1 -0
- package/dist/{odata → odata-service}/findCollectionPairs.d.ts +1 -1
- package/dist/odata-service/findCollectionPairs.d.ts.map +1 -0
- package/dist/odata-service/index.d.ts +5 -0
- package/dist/odata-service/index.d.ts.map +1 -1
- package/dist/odata-service/index.js +2 -2
- package/dist/{odata/store.d.ts → odata-service/odataCollectionStore.d.ts} +1 -1
- package/dist/odata-service/odataCollectionStore.d.ts.map +1 -0
- package/dist/query-client/index.js.map +1 -1
- package/dist/query-client/queryClient.d.ts +1 -3
- package/dist/query-client/queryClient.d.ts.map +1 -1
- package/package.json +1 -5
- package/src/array/README.mdx +1630 -0
- package/src/binary/README.mdx +1405 -0
- package/src/bounded-copy-stack/README.mdx +257 -0
- package/src/context-menu/README.mdx +326 -0
- package/src/copy/README.mdx +992 -0
- package/src/crypto/README.mdx +1052 -0
- package/src/currency/README.mdx +155 -0
- package/src/date-segments/README.mdx +319 -0
- package/src/dom/README.mdx +2179 -0
- package/src/error/README.mdx +95 -0
- package/src/error-report/README.mdx +612 -0
- package/src/excel/README.mdx +449 -0
- package/src/file/README.mdx +1957 -0
- package/src/fingerprint/README.mdx +100 -0
- package/src/form/README.mdx +101 -0
- package/src/formatters/README.mdx +469 -0
- package/src/formatters/boolean/README.mdx +494 -0
- package/src/formatters/date/README.mdx +732 -0
- package/src/formatters/number/README.mdx +542 -0
- package/src/formatters/pipeline/README.mdx +629 -0
- package/src/formatters/rowBased/README.mdx +486 -0
- package/src/formatters/strings/README.mdx +442 -0
- package/src/formatters/valueState/README.mdx +459 -0
- package/src/formulas/README.mdx +1283 -0
- package/src/foundationLib.mdx +70 -54
- package/src/hooks/README.mdx +988 -0
- package/src/http/README.mdx +126 -0
- package/src/media/README.mdx +1853 -0
- package/src/notifications/README.mdx +323 -0
- package/src/number-scale/README.mdx +318 -0
- package/src/odata-service/README.mdx +2916 -0
- package/src/presets/README.mdx +136 -0
- package/src/pwa/README.mdx +394 -0
- package/src/query-client/README.mdx +2500 -0
- package/src/range-output/README.mdx +161 -0
- package/src/seo/README.mdx +279 -0
- package/src/session-storage/README.mdx +125 -0
- package/src/string-comparison/README.mdx +96 -0
- package/src/table/README.mdx +3106 -0
- package/src/three-scene/README.mdx +248 -0
- package/src/types/README.mdx +172 -0
- package/src/utils/README.mdx +1724 -0
- package/src/validators/README.mdx +239 -0
- package/src/virtualizer/README.mdx +138 -0
- package/src/xml/README.mdx +149 -0
- package/dist/chunks/dateUtils-B5V5aXB-.js +0 -847
- package/dist/chunks/dateUtils-B5V5aXB-.js.map +0 -1
- package/dist/chunks/odata-service-B6TxBSLm.js +0 -1277
- package/dist/chunks/odata-service-B6TxBSLm.js.map +0 -1
- package/dist/odata/buildSeparatedArrays.d.ts.map +0 -1
- package/dist/odata/dateUtils.d.ts.map +0 -1
- package/dist/odata/findCollectionPairs.d.ts.map +0 -1
- package/dist/odata/index.d.ts +0 -6
- package/dist/odata/index.d.ts.map +0 -1
- package/dist/odata/index.js +0 -102
- package/dist/odata/index.js.map +0 -1
- package/dist/odata/store.d.ts.map +0 -1
- package/dist/odata/types.d.ts.map +0 -1
- package/src/binary/README.md +0 -110
- package/src/docs/browserAndReact.mdx +0 -150
- package/src/docs/filesAndExcel.mdx +0 -163
- package/src/docs/formatters-runtime.mdx +0 -455
- package/src/docs/formatters.mdx +0 -380
- package/src/docs/odataAndTables.mdx +0 -178
- package/src/docs/pureUtilities.mdx +0 -96
- package/src/docs/runtimeAndState.mdx +0 -155
- package/src/file/README.md +0 -289
- package/src/formatters/date/README.md +0 -520
- package/src/formatters/number/README.md +0 -123
- package/src/formatters/valueState/README.md +0 -275
- package/src/formulas/README.md +0 -42
- package/src/pwa/README.md +0 -638
- package/src/query-client/README.md +0 -565
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { Meta } from "@storybook/addon-docs/blocks";
|
|
2
|
+
|
|
3
|
+
<Meta title="Foundation Lib/Browser/Three Scene" />
|
|
4
|
+
|
|
5
|
+
# Three Scene
|
|
6
|
+
|
|
7
|
+
Модуль `@ryuzaki13/react-foundation-lib/three-scene` проверяет, можно ли безопасно показывать необязательную Three.js/WebGL-сцену, и помогает отключить её до конца браузерной сессии.
|
|
8
|
+
|
|
9
|
+
Модуль не импортирует Three.js, не создаёт renderer и не управляет canvas. Его задача — принять раннее решение: загружать тяжёлую 3D-сцену или показать облегчённую альтернативу.
|
|
10
|
+
|
|
11
|
+
## Когда использовать
|
|
12
|
+
|
|
13
|
+
Подходит для декоративных и дополнительных сцен:
|
|
14
|
+
|
|
15
|
+
- 3D-фон страницы;
|
|
16
|
+
- визуализация, у которой есть обычная HTML-альтернатива;
|
|
17
|
+
- lazy import Three.js только на поддерживаемых устройствах;
|
|
18
|
+
- отключение повторных неудачных попыток WebGL в пределах вкладки.
|
|
19
|
+
|
|
20
|
+
Для критически важного бизнес-сценария одной проверки поддержки недостаточно: renderer всё равно может завершиться ошибкой позже, например из-за потери контекста или нехватки памяти.
|
|
21
|
+
|
|
22
|
+
## Импорт
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import {
|
|
26
|
+
disableThreeSceneForSession,
|
|
27
|
+
isThreeSceneDisabledForSession,
|
|
28
|
+
isThreeSceneSupported,
|
|
29
|
+
threeSceneDefaultDisabledStorageKey,
|
|
30
|
+
useThreeSceneAvailability,
|
|
31
|
+
type ThreeSceneAvailability
|
|
32
|
+
} from "@ryuzaki13/react-foundation-lib/three-scene";
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Для hook нужен React. Остальные функции работают напрямую с браузерными API.
|
|
36
|
+
|
|
37
|
+
## Быстрый старт с React
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { lazy, Suspense } from "react";
|
|
41
|
+
import { useThreeSceneAvailability } from "@ryuzaki13/react-foundation-lib/three-scene";
|
|
42
|
+
|
|
43
|
+
const Scene = lazy(() => import("./Scene"));
|
|
44
|
+
|
|
45
|
+
export function HeroVisual() {
|
|
46
|
+
const availability = useThreeSceneAvailability({
|
|
47
|
+
webGLVersion: "webgl2",
|
|
48
|
+
disableWhenReducedMotion: true
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (availability.status !== "available") {
|
|
52
|
+
return <img src="/hero.webp" alt="" />;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<Suspense fallback={<img src="/hero.webp" alt="" />}>
|
|
57
|
+
<Scene />
|
|
58
|
+
</Suspense>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
На первом клиентском рендере hook тоже возвращает `unavailable/ssr`. Проверка происходит в effect после hydration. Это сохраняет одинаковую начальную HTML-разметку на сервере и клиенте.
|
|
64
|
+
|
|
65
|
+
## Модель состояния
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
type ThreeSceneAvailabilityStatus = "pending" | "available" | "unavailable";
|
|
69
|
+
|
|
70
|
+
type ThreeSceneUnavailableReason = "ssr" | "sessionDisabled" | "reducedMotion" | "webglUnsupported";
|
|
71
|
+
|
|
72
|
+
type ThreeSceneAvailability = {
|
|
73
|
+
readonly status: ThreeSceneAvailabilityStatus;
|
|
74
|
+
readonly reason?: ThreeSceneUnavailableReason;
|
|
75
|
+
};
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Текущий hook фактически возвращает `available` или `unavailable`; начальное состояние — `unavailable` с причиной `ssr`. Значение `pending` входит в общий тип, но hook сейчас его не устанавливает.
|
|
79
|
+
|
|
80
|
+
Причины:
|
|
81
|
+
|
|
82
|
+
| Причина | Значение |
|
|
83
|
+
| ------------------ | -------------------------------------------------------------------------------- |
|
|
84
|
+
| `ssr` | Проверка ещё не выполнена в браузере либо код работает без DOM |
|
|
85
|
+
| `sessionDisabled` | Сцена отключена в `sessionStorage` текущей вкладки |
|
|
86
|
+
| `reducedMotion` | Пользователь предпочитает уменьшенное движение, а соответствующая опция включена |
|
|
87
|
+
| `webglUnsupported` | Не удалось создать требуемый WebGL-контекст |
|
|
88
|
+
|
|
89
|
+
## `isThreeSceneSupported(options?)`
|
|
90
|
+
|
|
91
|
+
Синхронно проверяет создание WebGL-контекста на временном canvas.
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
isThreeSceneSupported(); // проверяет только WebGL 2
|
|
95
|
+
isThreeSceneSupported({ webGLVersion: "webgl2" });
|
|
96
|
+
isThreeSceneSupported({ webGLVersion: "webgl" });
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Доступны два режима:
|
|
100
|
+
|
|
101
|
+
- `webgl2` — принимает только контекст `webgl2`;
|
|
102
|
+
- `webgl` — пробует `webgl2`, затем `webgl` и `experimental-webgl`.
|
|
103
|
+
|
|
104
|
+
Если контекст создан, функция по возможности вызывает расширение `WEBGL_lose_context`, чтобы освободить временный ресурс. При отсутствии `document`, ошибке браузера или невозможности создать контекст возвращается `false`.
|
|
105
|
+
|
|
106
|
+
Положительный результат означает только базовую поддержку контекста. Он не гарантирует нужные extensions, производительность GPU, объём памяти или успешную загрузку конкретной сцены.
|
|
107
|
+
|
|
108
|
+
## Отключение на время сессии
|
|
109
|
+
|
|
110
|
+
### Ключ по умолчанию
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
threeSceneDefaultDisabledStorageKey;
|
|
114
|
+
// `${__APP_ID__}:three-scene:disabled`
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Пакет ожидает, что сборка приложения определит compile-time константу `__APP_ID__`. Она отделяет данные разных приложений на одном origin.
|
|
118
|
+
|
|
119
|
+
### `disableThreeSceneForSession(storageKey?)`
|
|
120
|
+
|
|
121
|
+
Записывает строку `"1"` в `sessionStorage`. Функция ничего не делает на сервере и молча игнорирует ошибки хранилища.
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
try {
|
|
125
|
+
await startScene();
|
|
126
|
+
} catch (error) {
|
|
127
|
+
disableThreeSceneForSession();
|
|
128
|
+
showStaticFallback();
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`sessionStorage` живёт в пределах вкладки. Новая вкладка или новая сессия получает новую попытку.
|
|
133
|
+
|
|
134
|
+
### `isThreeSceneDisabledForSession(storageKey?)`
|
|
135
|
+
|
|
136
|
+
Возвращает `true`, только если по ключу хранится точная строка `"1"`. На сервере возвращает `true`, чтобы сцена не пыталась стартовать без браузера. Если чтение storage бросает исключение, возвращается `false` — недоступность storage сама по себе не отключает WebGL.
|
|
137
|
+
|
|
138
|
+
### Собственный ключ
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
const storageKey = "dashboard:analytics-scene:disabled";
|
|
142
|
+
|
|
143
|
+
disableThreeSceneForSession(storageKey);
|
|
144
|
+
isThreeSceneDisabledForSession(storageKey);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Одинаковый ключ нужно передавать и в hook.
|
|
148
|
+
|
|
149
|
+
## `useThreeSceneAvailability(options?)`
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
type UseThreeSceneAvailabilityOptions = {
|
|
153
|
+
readonly disabledStorageKey?: string;
|
|
154
|
+
readonly disableWhenReducedMotion?: boolean;
|
|
155
|
+
readonly webGLVersion?: "webgl" | "webgl2";
|
|
156
|
+
};
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Значения по умолчанию:
|
|
160
|
+
|
|
161
|
+
- `disabledStorageKey` — `threeSceneDefaultDisabledStorageKey`;
|
|
162
|
+
- `disableWhenReducedMotion` — `false`;
|
|
163
|
+
- `webGLVersion` — `webgl2`.
|
|
164
|
+
|
|
165
|
+
После монтирования проверки выполняются в строгом порядке:
|
|
166
|
+
|
|
167
|
+
1. включённая политика reduced motion;
|
|
168
|
+
2. флаг отключения в sessionStorage;
|
|
169
|
+
3. поддержка требуемого WebGL;
|
|
170
|
+
4. состояние `available`.
|
|
171
|
+
|
|
172
|
+
Если WebGL не поддержан, hook автоматически записывает session-флаг. Следующие проверки в этой вкладке сразу получат `sessionDisabled` и не будут повторно создавать пробный контекст.
|
|
173
|
+
|
|
174
|
+
Hook повторяет вычисление, если меняются options или результат media query `prefers-reduced-motion`.
|
|
175
|
+
|
|
176
|
+
## Reduced motion
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
const availability = useThreeSceneAvailability({
|
|
180
|
+
disableWhenReducedMotion: true
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
При `true` сцена отключается для пользователя с настройкой `prefers-reduced-motion: reduce`. Сам session-флаг при этом не записывается: если пользователь изменит системную настройку, hook сможет пересчитать состояние.
|
|
185
|
+
|
|
186
|
+
Если 3D-сцена не содержит значимого движения или имеет собственный облегчённый режим, приложение может оставить опцию `false` и применить reduced-motion внутри renderer.
|
|
187
|
+
|
|
188
|
+
## Восстановление после ошибки
|
|
189
|
+
|
|
190
|
+
Модуль не экспортирует `enableThreeSceneForSession`. Чтобы дать пользователю кнопку «Попробовать снова», приложение может удалить тот же ключ и перезагрузить/перемонтировать проверку:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
window.sessionStorage.removeItem(threeSceneDefaultDisabledStorageKey);
|
|
194
|
+
window.location.reload();
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Удаление storage и reload — решение приложения, потому что повторный запуск тяжёлой сцены должен быть явным пользовательским действием.
|
|
198
|
+
|
|
199
|
+
## Рекомендуемая граница загрузки
|
|
200
|
+
|
|
201
|
+
Не импортируйте тяжёлую сцену до проверки:
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
// Хорошо: код сцены загружается отдельным chunk только при рендере Scene.
|
|
205
|
+
const Scene = lazy(() => import("./Scene"));
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Статический `import Scene from "./Scene"` загрузит Three.js даже если компонент затем вернёт fallback.
|
|
209
|
+
|
|
210
|
+
После `available` всё равно ставьте error boundary вокруг сцены. Runtime-ошибка renderer не меняет availability автоматически.
|
|
211
|
+
|
|
212
|
+
## SSR и hydration
|
|
213
|
+
|
|
214
|
+
- `isThreeSceneSupported` на сервере возвращает `false`.
|
|
215
|
+
- `isThreeSceneDisabledForSession` на сервере возвращает `true`.
|
|
216
|
+
- hook начинает с детерминированного `unavailable/ssr`.
|
|
217
|
+
- фактическая проверка выполняется только в `useEffect`.
|
|
218
|
+
|
|
219
|
+
Поэтому сервер должен рендерить статический fallback. Не считайте начальную причину `ssr` окончательным отказом браузера.
|
|
220
|
+
|
|
221
|
+
## Частые ошибки
|
|
222
|
+
|
|
223
|
+
### Считать WebGL-проверку benchmark
|
|
224
|
+
|
|
225
|
+
Функция проверяет возможность создания контекста, но не измеряет FPS и не оценивает сложность сцены.
|
|
226
|
+
|
|
227
|
+
### Запускать сцену во время SSR
|
|
228
|
+
|
|
229
|
+
Canvas, sessionStorage и WebGL — browser-only API. Загружайте и запускайте renderer после `availability.status === "available"`.
|
|
230
|
+
|
|
231
|
+
### Не определить `__APP_ID__`
|
|
232
|
+
|
|
233
|
+
Значение участвует в ключе storage на этапе выполнения собранного кода. Сборщик потребителя должен заменить эту compile-time константу.
|
|
234
|
+
|
|
235
|
+
### Ожидать автоматического отключения при любой runtime-ошибке
|
|
236
|
+
|
|
237
|
+
Автоматический session-флаг ставится только при неуспешной первоначальной проверке WebGL. Ошибки загрузки ассетов и renderer приложение обрабатывает самостоятельно.
|
|
238
|
+
|
|
239
|
+
## Краткая карта API
|
|
240
|
+
|
|
241
|
+
| Экспорт | Назначение |
|
|
242
|
+
| ------------------------------------- | ----------------------------------------------------------- |
|
|
243
|
+
| `isThreeSceneSupported()` | Проверить возможность создать WebGL-контекст |
|
|
244
|
+
| `disableThreeSceneForSession()` | Отключить сцену до конца сессии вкладки |
|
|
245
|
+
| `isThreeSceneDisabledForSession()` | Прочитать session-флаг |
|
|
246
|
+
| `threeSceneDefaultDisabledStorageKey` | Ключ storage с namespace приложения |
|
|
247
|
+
| `useThreeSceneAvailability()` | Объединить WebGL, session и reduced-motion проверки в React |
|
|
248
|
+
| `ThreeSceneAvailability` | Тип результата availability |
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { Meta } from "@storybook/addon-docs/blocks";
|
|
2
|
+
|
|
3
|
+
<Meta title="Foundation Lib/Contracts/Common Types" />
|
|
4
|
+
|
|
5
|
+
# Общие технические типы `@ryuzaki13/react-foundation-lib/types`
|
|
6
|
+
|
|
7
|
+
Модуль содержит небольшие общие TypeScript-контракты для value state, ABAP boolean, базовых значений, диапазонов и строк таблицы. Единственная runtime-функция — `isBaseType`.
|
|
8
|
+
|
|
9
|
+
## Содержание
|
|
10
|
+
|
|
11
|
+
- [Установка и импорт](#установка-и-импорт)
|
|
12
|
+
- [`State`](#state)
|
|
13
|
+
- [`AbapBoolean`](#abapboolean)
|
|
14
|
+
- [`Primitive` и `BaseType`](#primitive-и-basetype)
|
|
15
|
+
- [`isBaseType`](#isbasetype)
|
|
16
|
+
- [`ArrayType`, `ObjectType`, `InputType`](#arraytype-objecttype-inputtype)
|
|
17
|
+
- [`RangeType`](#rangetype)
|
|
18
|
+
- [`RowRecord`](#rowrecord)
|
|
19
|
+
- [Ошибки проектирования](#ошибки-проектирования)
|
|
20
|
+
|
|
21
|
+
## Установка и импорт
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { isBaseType } from "@ryuzaki13/react-foundation-lib/types";
|
|
25
|
+
|
|
26
|
+
import type {
|
|
27
|
+
AbapBoolean,
|
|
28
|
+
ArrayType,
|
|
29
|
+
BaseType,
|
|
30
|
+
InputType,
|
|
31
|
+
ObjectType,
|
|
32
|
+
Primitive,
|
|
33
|
+
RangeType,
|
|
34
|
+
RowRecord,
|
|
35
|
+
State
|
|
36
|
+
} from "@ryuzaki13/react-foundation-lib/types";
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Типы исчезают после компиляции TypeScript. Не пытайтесь использовать `State` или `RowRecord` как runtime validator.
|
|
40
|
+
|
|
41
|
+
## `State`
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
type State = "" | "none" | "information" | "success" | "warning" | "error";
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Это общий display/value state, а не HTTP status и не состояние async request.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
const state: State = "warning";
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Пустая строка и `"none"` являются разными допустимыми значениями. Не сжимайте их автоматически в `undefined`, если contract этого не требует.
|
|
54
|
+
|
|
55
|
+
## `AbapBoolean`
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
type AbapBoolean = "X" | " ";
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
ABAP-style boolean использует `"X"` для истины и строку из одного пробела для лжи. Это не JavaScript boolean:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
Boolean(" "); // true, потому что непустая строка.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Для преобразования используйте boolean formatters, а не `Boolean(value)`.
|
|
68
|
+
|
|
69
|
+
## `Primitive` и `BaseType`
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
type Primitive = string | number | boolean | null | undefined;
|
|
73
|
+
type BaseType = Date | Primitive;
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`BaseType` добавляет `Date` к primitive values. Тип `number` статически включает `NaN`/`Infinity`, но runtime guard их отклоняет.
|
|
77
|
+
|
|
78
|
+
## `isBaseType`
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
isBaseType("text"); // true.
|
|
82
|
+
isBaseType(10); // true.
|
|
83
|
+
isBaseType(false); // true.
|
|
84
|
+
isBaseType(null); // true.
|
|
85
|
+
isBaseType(undefined); // true.
|
|
86
|
+
isBaseType(new Date()); // true.
|
|
87
|
+
|
|
88
|
+
isBaseType(Number.NaN); // false.
|
|
89
|
+
isBaseType(Infinity); // false.
|
|
90
|
+
isBaseType(new Date("bad")); // false.
|
|
91
|
+
isBaseType([]); // false.
|
|
92
|
+
isBaseType({}); // false.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Сигнатура является type guard:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
function acceptUnknown(value: unknown) {
|
|
99
|
+
if (!isBaseType(value)) return;
|
|
100
|
+
|
|
101
|
+
// Здесь value имеет тип BaseType.
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Guard проверяет только форму базового значения, а не бизнес-ограничения строки/числа/даты.
|
|
106
|
+
|
|
107
|
+
## `ArrayType`, `ObjectType`, `InputType`
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
type ArrayType = BaseType[];
|
|
111
|
+
type ObjectType = Readonly<Record<string, BaseType>> | object;
|
|
112
|
+
type InputType = BaseType | ArrayType | ObjectType;
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`ArrayType` — изменяемый массив базовых значений.
|
|
116
|
+
|
|
117
|
+
`ObjectType` намеренно широкий: union с `object` допускает практически любой non-primitive object. Он не означает JSON-compatible record и не является runtime-проверкой.
|
|
118
|
+
|
|
119
|
+
`InputType` объединяет базовые значения, массивы и objects для generic formatter/input contracts. Не используйте его вместо точного domain DTO.
|
|
120
|
+
|
|
121
|
+
## `RangeType`
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
type RangeType = readonly [BaseType | null, BaseType | null];
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Tuple всегда имеет две позиции:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
const range: RangeType = [new Date(2026, 0, 1), null];
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- индекс `0` — начало;
|
|
134
|
+
- индекс `1` — конец;
|
|
135
|
+
- `null` обычно означает открытую/незаполненную границу;
|
|
136
|
+
- `readonly` запрещает присваивание через TypeScript, но не вызывает `Object.freeze`.
|
|
137
|
+
|
|
138
|
+
Поскольку `BaseType` уже включает `null` и `undefined`, тип исторически широкий. Конкретный UI/domain contract должен задавать более точный `readonly [T | null, T | null]`.
|
|
139
|
+
|
|
140
|
+
## `RowRecord`
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
type RowRecord = Record<string, unknown>;
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Это строка таблицы с неизвестными полями. Перед использованием значения его нужно сузить:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
function readName(row: RowRecord): string | undefined {
|
|
150
|
+
return typeof row.name === "string" ? row.name : undefined;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Если структура известна, объявляйте точный тип:
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
type EmployeeRow = {
|
|
158
|
+
id: string;
|
|
159
|
+
name: string;
|
|
160
|
+
salary: number;
|
|
161
|
+
};
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Ошибки проектирования
|
|
165
|
+
|
|
166
|
+
- Использовать `InputType` как замену schema внешнего JSON.
|
|
167
|
+
- Считать `ObjectType` plain object.
|
|
168
|
+
- Приводить `AbapBoolean` через `Boolean()`.
|
|
169
|
+
- Считать `readonly` runtime-заморозкой.
|
|
170
|
+
- Использовать `RowRecord` там, где известны поля сущности.
|
|
171
|
+
- Считать `isBaseType` проверкой диапазона, длины или разрешённых business values.
|
|
172
|
+
- Нормализовать `""`, `false`, `[]` и `null` только из-за широкого общего типа.
|