@umituz/react-native-design-system 2.8.7 → 2.8.8
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/package.json +5 -6
- package/src/device/infrastructure/repositories/LegacyDeviceIdRepository.ts +1 -1
- package/src/device/infrastructure/services/DeviceFeatureService.ts +1 -1
- package/src/exception/infrastructure/services/ExceptionLogger.ts +1 -1
- package/src/exception/infrastructure/storage/ExceptionStore.ts +1 -1
- package/src/exports/filesystem.ts +1 -0
- package/src/exports/storage.ts +1 -0
- package/src/filesystem/domain/constants/FileConstants.ts +20 -0
- package/src/filesystem/domain/entities/File.ts +20 -0
- package/src/filesystem/domain/types/FileTypes.ts +43 -0
- package/src/filesystem/domain/utils/FileUtils.ts +86 -0
- package/src/filesystem/index.ts +23 -0
- package/src/filesystem/infrastructure/services/FileSystemService.ts +45 -0
- package/src/filesystem/infrastructure/services/cache.service.ts +48 -0
- package/src/filesystem/infrastructure/services/directory.service.ts +66 -0
- package/src/filesystem/infrastructure/services/download.constants.ts +6 -0
- package/src/filesystem/infrastructure/services/download.service.ts +74 -0
- package/src/filesystem/infrastructure/services/download.types.ts +7 -0
- package/src/filesystem/infrastructure/services/encoding.service.ts +25 -0
- package/src/filesystem/infrastructure/services/file-info.service.ts +52 -0
- package/src/filesystem/infrastructure/services/file-manager.service.ts +81 -0
- package/src/filesystem/infrastructure/services/file-path.service.ts +22 -0
- package/src/filesystem/infrastructure/services/file-reader.service.ts +52 -0
- package/src/filesystem/infrastructure/services/file-writer.service.ts +32 -0
- package/src/filesystem/infrastructure/utils/blob.utils.ts +20 -0
- package/src/image/infrastructure/services/ImageStorageService.ts +1 -1
- package/src/index.ts +9 -0
- package/src/molecules/alerts/AlertStore.ts +1 -1
- package/src/molecules/calendar/infrastructure/storage/EventActions.ts +1 -1
- package/src/molecules/calendar/infrastructure/stores/storageAdapter.ts +1 -1
- package/src/offline/infrastructure/storage/OfflineStore.ts +1 -1
- package/src/onboarding/infrastructure/storage/OnboardingStore.ts +2 -2
- package/src/onboarding/infrastructure/storage/__tests__/OnboardingStore.test.ts +1 -1
- package/src/onboarding/infrastructure/storage/actions/answerActions.ts +1 -1
- package/src/onboarding/infrastructure/storage/actions/storageHelpers.ts +1 -1
- package/src/storage/README.md +185 -0
- package/src/storage/__tests__/integration.test.ts +391 -0
- package/src/storage/__tests__/mocks/asyncStorage.mock.ts +52 -0
- package/src/storage/__tests__/performance.test.tsx +352 -0
- package/src/storage/__tests__/setup.ts +63 -0
- package/src/storage/application/README.md +158 -0
- package/src/storage/application/ports/IStorageRepository.ts +61 -0
- package/src/storage/application/ports/README.md +127 -0
- package/src/storage/cache/README.md +154 -0
- package/src/storage/cache/__tests__/PerformanceAndMemory.test.ts +387 -0
- package/src/storage/cache/__tests__/setup.ts +19 -0
- package/src/storage/cache/domain/Cache.ts +146 -0
- package/src/storage/cache/domain/CacheManager.md +83 -0
- package/src/storage/cache/domain/CacheManager.ts +48 -0
- package/src/storage/cache/domain/CacheStatsTracker.md +169 -0
- package/src/storage/cache/domain/CacheStatsTracker.ts +49 -0
- package/src/storage/cache/domain/CachedValue.md +97 -0
- package/src/storage/cache/domain/ErrorHandler.md +99 -0
- package/src/storage/cache/domain/ErrorHandler.ts +42 -0
- package/src/storage/cache/domain/PatternMatcher.md +122 -0
- package/src/storage/cache/domain/PatternMatcher.ts +30 -0
- package/src/storage/cache/domain/README.md +118 -0
- package/src/storage/cache/domain/__tests__/Cache.test.ts +293 -0
- package/src/storage/cache/domain/__tests__/CacheManager.test.ts +276 -0
- package/src/storage/cache/domain/__tests__/ErrorHandler.test.ts +303 -0
- package/src/storage/cache/domain/__tests__/PatternMatcher.test.ts +261 -0
- package/src/storage/cache/domain/strategies/EvictionStrategy.ts +9 -0
- package/src/storage/cache/domain/strategies/FIFOStrategy.ts +12 -0
- package/src/storage/cache/domain/strategies/LFUStrategy.ts +22 -0
- package/src/storage/cache/domain/strategies/LRUStrategy.ts +22 -0
- package/src/storage/cache/domain/strategies/README.md +117 -0
- package/src/storage/cache/domain/strategies/TTLStrategy.ts +23 -0
- package/src/storage/cache/domain/strategies/__tests__/EvictionStrategies.test.ts +293 -0
- package/src/storage/cache/domain/types/Cache.ts +28 -0
- package/src/storage/cache/domain/types/README.md +107 -0
- package/src/storage/cache/index.ts +28 -0
- package/src/storage/cache/infrastructure/README.md +126 -0
- package/src/storage/cache/infrastructure/TTLCache.ts +103 -0
- package/src/storage/cache/infrastructure/__tests__/TTLCache.test.ts +303 -0
- package/src/storage/cache/presentation/README.md +123 -0
- package/src/storage/cache/presentation/__tests__/ReactHooks.test.ts +514 -0
- package/src/storage/cache/presentation/useCache.ts +76 -0
- package/src/storage/cache/presentation/useCachedValue.ts +88 -0
- package/src/storage/cache/types.d.ts +3 -0
- package/src/storage/domain/README.md +128 -0
- package/src/storage/domain/constants/CacheDefaults.ts +64 -0
- package/src/storage/domain/constants/README.md +105 -0
- package/src/storage/domain/entities/CachedValue.ts +86 -0
- package/src/storage/domain/entities/README.md +109 -0
- package/src/storage/domain/entities/StorageResult.ts +75 -0
- package/src/storage/domain/entities/__tests__/CachedValue.test.ts +149 -0
- package/src/storage/domain/entities/__tests__/StorageResult.test.ts +122 -0
- package/src/storage/domain/errors/README.md +126 -0
- package/src/storage/domain/errors/StorageError.ts +81 -0
- package/src/storage/domain/errors/__tests__/StorageError.test.ts +127 -0
- package/src/storage/domain/factories/README.md +138 -0
- package/src/storage/domain/factories/StoreFactory.ts +59 -0
- package/src/storage/domain/types/README.md +522 -0
- package/src/storage/domain/types/Store.ts +44 -0
- package/src/storage/domain/utils/CacheKeyGenerator.ts +66 -0
- package/src/storage/domain/utils/README.md +127 -0
- package/src/storage/domain/utils/__tests__/devUtils.test.ts +97 -0
- package/src/storage/domain/utils/devUtils.ts +37 -0
- package/src/storage/domain/value-objects/README.md +120 -0
- package/src/storage/domain/value-objects/StorageKey.ts +60 -0
- package/src/storage/index.ts +175 -0
- package/src/storage/infrastructure/README.md +165 -0
- package/src/storage/infrastructure/adapters/README.md +175 -0
- package/src/storage/infrastructure/adapters/StorageService.md +103 -0
- package/src/storage/infrastructure/adapters/StorageService.ts +49 -0
- package/src/storage/infrastructure/repositories/AsyncStorageRepository.ts +98 -0
- package/src/storage/infrastructure/repositories/BaseStorageOperations.ts +100 -0
- package/src/storage/infrastructure/repositories/BatchStorageOperations.ts +42 -0
- package/src/storage/infrastructure/repositories/README.md +121 -0
- package/src/storage/infrastructure/repositories/StringStorageOperations.ts +44 -0
- package/src/storage/infrastructure/repositories/__tests__/AsyncStorageRepository.test.ts +170 -0
- package/src/storage/infrastructure/repositories/__tests__/BaseStorageOperations.test.ts +201 -0
- package/src/storage/presentation/README.md +181 -0
- package/src/storage/presentation/hooks/CacheStorageOperations.ts +94 -0
- package/src/storage/presentation/hooks/README.md +128 -0
- package/src/storage/presentation/hooks/__tests__/usePersistentCache.test.ts +405 -0
- package/src/storage/presentation/hooks/__tests__/useStorage.test.ts +247 -0
- package/src/storage/presentation/hooks/__tests__/useStorageState.test.ts +293 -0
- package/src/storage/presentation/hooks/useCacheState.ts +53 -0
- package/src/storage/presentation/hooks/usePersistentCache.ts +154 -0
- package/src/storage/presentation/hooks/useStorage.ts +102 -0
- package/src/storage/presentation/hooks/useStorageState.ts +71 -0
- package/src/storage/presentation/hooks/useStore.ts +15 -0
- package/src/storage/types/README.md +103 -0
- package/src/theme/infrastructure/globalThemeStore.ts +1 -1
- package/src/theme/infrastructure/storage/ThemeStorage.ts +1 -1
- package/src/theme/infrastructure/stores/themeStore.ts +1 -1
- package/src/utilities/sharing/infrastructure/services/SharingService.ts +1 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Domain Factories
|
|
2
|
+
|
|
3
|
+
Factory functions for creating Zustand stores with persistence.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Factory functions for creating Zustand stores with AsyncStorage persistence. Located at `src/domain/factories/`.
|
|
8
|
+
|
|
9
|
+
## Strategies
|
|
10
|
+
|
|
11
|
+
### Store Creation
|
|
12
|
+
- Use createStore() factory for all Zustand stores
|
|
13
|
+
- Provide type inference for state and actions
|
|
14
|
+
- Support optional persistence
|
|
15
|
+
- Enable store composition
|
|
16
|
+
|
|
17
|
+
### Persistence Strategy
|
|
18
|
+
- Use persist middleware for AsyncStorage integration
|
|
19
|
+
- Configure storage adapter (StorageService)
|
|
20
|
+
- Support selective persistence (partialize)
|
|
21
|
+
- Enable versioning and migration
|
|
22
|
+
|
|
23
|
+
### Store Configuration
|
|
24
|
+
- Require unique store name
|
|
25
|
+
- Define initial state clearly
|
|
26
|
+
- Create actions with set/get helpers
|
|
27
|
+
- Support middleware configuration
|
|
28
|
+
|
|
29
|
+
### Type Safety
|
|
30
|
+
- Infer state types from initial state
|
|
31
|
+
- Separate state and actions types
|
|
32
|
+
- Enable type-safe selectors
|
|
33
|
+
- Support generic store types
|
|
34
|
+
|
|
35
|
+
## Restrictions
|
|
36
|
+
|
|
37
|
+
### Store Creation
|
|
38
|
+
- DO NOT create stores without factory
|
|
39
|
+
- DO NOT duplicate store names
|
|
40
|
+
- DO NOT mix state and actions unnecessarily
|
|
41
|
+
- DO NOT create stores without clear purpose
|
|
42
|
+
|
|
43
|
+
### Persistence
|
|
44
|
+
- DO NOT enable persist without unique name
|
|
45
|
+
- DO NOT persist sensitive data without encryption
|
|
46
|
+
- DO NOT forget version when schema changes
|
|
47
|
+
- DO NOT omit migration for breaking changes
|
|
48
|
+
|
|
49
|
+
### Type Safety
|
|
50
|
+
- DO NOT use `any` for state type
|
|
51
|
+
- DO NOT bypass type inference
|
|
52
|
+
- DO NOT cast state to wrong type
|
|
53
|
+
- DO NOT create circular type dependencies
|
|
54
|
+
|
|
55
|
+
## Rules
|
|
56
|
+
|
|
57
|
+
### Factory Function
|
|
58
|
+
- MUST provide createStore(config) function
|
|
59
|
+
- MUST accept name parameter (required)
|
|
60
|
+
- MUST accept initialState parameter (required)
|
|
61
|
+
- MUST accept actions parameter (optional)
|
|
62
|
+
- MUST accept persist parameter (optional)
|
|
63
|
+
|
|
64
|
+
### Store Configuration
|
|
65
|
+
- MUST require unique store name
|
|
66
|
+
- MUST define complete initial state
|
|
67
|
+
- MUST provide type inference
|
|
68
|
+
- MUST validate configuration
|
|
69
|
+
- MUST return configured store
|
|
70
|
+
|
|
71
|
+
### Persistence Setup
|
|
72
|
+
- MUST use zustand persist middleware
|
|
73
|
+
- MUST use storageService adapter
|
|
74
|
+
- MUST include store name in config
|
|
75
|
+
- MUST support version parameter
|
|
76
|
+
- MUST support partialize function
|
|
77
|
+
|
|
78
|
+
### Actions Creation
|
|
79
|
+
- MUST provide set helper for updates
|
|
80
|
+
- MUST provide get helper for reads
|
|
81
|
+
- MUST support both object and function updates
|
|
82
|
+
- MUST enable action composition
|
|
83
|
+
- MUST preserve type safety
|
|
84
|
+
|
|
85
|
+
### Type Inference
|
|
86
|
+
- MUST infer state type from initialState
|
|
87
|
+
- MUST infer actions type from actions return
|
|
88
|
+
- MUST support ReturnType for external use
|
|
89
|
+
- MUST enable Pick for action subsets
|
|
90
|
+
|
|
91
|
+
### Version Management
|
|
92
|
+
- MUST increment version on schema changes
|
|
93
|
+
- MUST provide migrate function
|
|
94
|
+
- MUST handle old persisted states
|
|
95
|
+
- MUST document breaking changes
|
|
96
|
+
- MUST support multiple version migrations
|
|
97
|
+
|
|
98
|
+
### Partialize Function
|
|
99
|
+
- MUST accept full state parameter
|
|
100
|
+
- MUST return partial state for persistence
|
|
101
|
+
- MUST exclude transient state
|
|
102
|
+
- MUST include all persistent state
|
|
103
|
+
- MUST enable optimization
|
|
104
|
+
|
|
105
|
+
### Migration Function
|
|
106
|
+
- MUST accept persistedState parameter
|
|
107
|
+
- MUST accept version parameter
|
|
108
|
+
- MUST return migrated state
|
|
109
|
+
- MUST handle all old versions
|
|
110
|
+
- MUST default to identity for current version
|
|
111
|
+
|
|
112
|
+
### OnRehydrate Callback
|
|
113
|
+
- MUST accept hydrated state parameter
|
|
114
|
+
- MUST execute after rehydration
|
|
115
|
+
- MUST enable initialization logic
|
|
116
|
+
- MUST not block hydration
|
|
117
|
+
- MUST support async operations
|
|
118
|
+
|
|
119
|
+
### Error Handling
|
|
120
|
+
- MUST validate store configuration
|
|
121
|
+
- MUST throw descriptive errors for invalid config
|
|
122
|
+
- MUST handle persistence errors gracefully
|
|
123
|
+
- MUST log errors in development
|
|
124
|
+
- MUST provide fallback when possible
|
|
125
|
+
|
|
126
|
+
### Testing Support
|
|
127
|
+
- MUST enable store reset in tests
|
|
128
|
+
- MUST support mocking persistence
|
|
129
|
+
- MUST provide test utilities
|
|
130
|
+
- MUST clear state between tests
|
|
131
|
+
- MUST not have hidden dependencies
|
|
132
|
+
|
|
133
|
+
### Documentation
|
|
134
|
+
- MUST document store purpose
|
|
135
|
+
- MUST specify state structure
|
|
136
|
+
- MUST document all actions
|
|
137
|
+
- MUST explain persistence strategy
|
|
138
|
+
- MUST warn about common mistakes
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store Factory
|
|
3
|
+
* Create Zustand stores with AsyncStorage persistence and actions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { create } from 'zustand';
|
|
7
|
+
import { persist, createJSONStorage } from 'zustand/middleware';
|
|
8
|
+
import type { StoreApi } from 'zustand';
|
|
9
|
+
import type { StoreConfig } from '../types/Store';
|
|
10
|
+
import { storageService } from '../../infrastructure/adapters/StorageService';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create a Zustand store with optional persistence and actions
|
|
14
|
+
*/
|
|
15
|
+
export function createStore<
|
|
16
|
+
TState extends object,
|
|
17
|
+
TActions extends object = object
|
|
18
|
+
>(config: StoreConfig<TState, TActions>) {
|
|
19
|
+
type Store = TState & TActions;
|
|
20
|
+
type SetState = StoreApi<Store>['setState'];
|
|
21
|
+
type GetState = StoreApi<Store>['getState'];
|
|
22
|
+
|
|
23
|
+
const stateCreator = (set: SetState, get: GetState): Store => {
|
|
24
|
+
const state = config.initialState as TState;
|
|
25
|
+
const actions = config.actions
|
|
26
|
+
? config.actions(set, get)
|
|
27
|
+
: ({} as TActions);
|
|
28
|
+
return { ...state, ...actions } as Store;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
if (!config.persist) {
|
|
32
|
+
return create<Store>(stateCreator);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return create<Store>()(
|
|
36
|
+
persist<Store>(stateCreator, {
|
|
37
|
+
name: config.name,
|
|
38
|
+
storage: createJSONStorage(() => storageService),
|
|
39
|
+
version: config.version || 1,
|
|
40
|
+
partialize: config.partialize
|
|
41
|
+
? (state: Store) => config.partialize!(state as any) as any
|
|
42
|
+
: (state: Store) => {
|
|
43
|
+
const persisted: Record<string, unknown> = {};
|
|
44
|
+
for (const key of Object.keys(state)) {
|
|
45
|
+
if (typeof state[key as keyof Store] !== 'function') {
|
|
46
|
+
persisted[key] = state[key as keyof Store];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return persisted as any;
|
|
50
|
+
},
|
|
51
|
+
onRehydrateStorage: () => (state: Store | undefined) => {
|
|
52
|
+
if (state && config.onRehydrate) {
|
|
53
|
+
config.onRehydrate(state as any);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
migrate: config.migrate as any,
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
# Domain Types
|
|
2
|
+
|
|
3
|
+
Storage domain için TypeScript tipleri ve interface'ler.
|
|
4
|
+
|
|
5
|
+
## Types
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import type {
|
|
9
|
+
StoreConfig,
|
|
10
|
+
PersistedState,
|
|
11
|
+
SetState,
|
|
12
|
+
GetState,
|
|
13
|
+
ActionsCreator,
|
|
14
|
+
} from '@umituz/react-native-storage';
|
|
15
|
+
|
|
16
|
+
import type {
|
|
17
|
+
StoreApi,
|
|
18
|
+
UseBoundStore,
|
|
19
|
+
} from 'zustand';
|
|
20
|
+
|
|
21
|
+
import type {
|
|
22
|
+
StateCreator,
|
|
23
|
+
StoreMutatorIdentifier,
|
|
24
|
+
} from 'zustand/vanilla';
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Store Types
|
|
28
|
+
|
|
29
|
+
### StoreConfig
|
|
30
|
+
|
|
31
|
+
Store konfigürasyonu için tip.
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
interface StoreConfig<TState, TActions> {
|
|
35
|
+
name: string;
|
|
36
|
+
initialState: TState;
|
|
37
|
+
actions?: ActionsCreator<TState, TActions>;
|
|
38
|
+
persist?: boolean;
|
|
39
|
+
version?: number;
|
|
40
|
+
partialize?: (state: TState & TActions) => Partial<TState>;
|
|
41
|
+
onRehydrate?: (state: TState & TActions) => void;
|
|
42
|
+
migrate?: (persistedState: unknown, version: number) => TState & TActions;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### PersistedState
|
|
47
|
+
|
|
48
|
+
Persist edilmiş state için tip.
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
interface PersistedState<T> {
|
|
52
|
+
version: number;
|
|
53
|
+
state: T;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### SetState
|
|
58
|
+
|
|
59
|
+
State güncelleme fonksiyonu tipi.
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
type SetState<T> = (
|
|
63
|
+
partial: Partial<T> | ((state: T) => Partial<T>),
|
|
64
|
+
replace?: boolean
|
|
65
|
+
) => void;
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### GetState
|
|
69
|
+
|
|
70
|
+
State okuma fonksiyonu tipi.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
type GetState<T> = () => T;
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### ActionsCreator
|
|
77
|
+
|
|
78
|
+
Action oluşturucu fonksiyon tipi.
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
type ActionsCreator<TState, TActions> = (
|
|
82
|
+
set: SetState<TState & TActions>,
|
|
83
|
+
get: GetState<TState & TActions>
|
|
84
|
+
) => TActions;
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Zustand Types
|
|
88
|
+
|
|
89
|
+
### StoreApi
|
|
90
|
+
|
|
91
|
+
Zustand store API tipi.
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
interface StoreApi<T> {
|
|
95
|
+
getState: () => T;
|
|
96
|
+
setState: (partial: Partial<T> | ((state: T) => Partial<T>), replace?: boolean) => void;
|
|
97
|
+
subscribe: (listener: (state: T, prevState: T) => void) => () => void;
|
|
98
|
+
destroy: () => void;
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### UseBoundStore
|
|
103
|
+
|
|
104
|
+
React hook tipi.
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
type UseBoundStore<T> = {
|
|
108
|
+
(): T;
|
|
109
|
+
<U>(selector: (state: T) => U, equalityFn?: (a: U, b: U) => boolean): U;
|
|
110
|
+
};
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### StateCreator
|
|
114
|
+
|
|
115
|
+
State oluşturucu tipi.
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
type StateCreator<T, Mis = []> = (
|
|
119
|
+
set: SetState<T>,
|
|
120
|
+
get: GetState<T>,
|
|
121
|
+
api: StoreApi<T>,
|
|
122
|
+
) => T;
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Kullanım Örnekleri
|
|
126
|
+
|
|
127
|
+
### Basit Store Type
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import type { StoreConfig } from '@umituz/react-native-storage';
|
|
131
|
+
|
|
132
|
+
interface CounterState {
|
|
133
|
+
count: number;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
interface CounterActions {
|
|
137
|
+
increment: () => void;
|
|
138
|
+
decrement: () => void;
|
|
139
|
+
reset: () => void;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
type CounterStore = CounterState & CounterActions;
|
|
143
|
+
|
|
144
|
+
const config: StoreConfig<CounterState, CounterActions> = {
|
|
145
|
+
name: 'counter',
|
|
146
|
+
initialState: { count: 0 },
|
|
147
|
+
actions: (set) => ({
|
|
148
|
+
increment: () => set((state) => ({ count: state.count + 1 })),
|
|
149
|
+
decrement: () => set((state) => ({ count: state.count - 1 })),
|
|
150
|
+
reset: () => set({ count: 0 }),
|
|
151
|
+
}),
|
|
152
|
+
};
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Generic Store Type
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
import type { StoreConfig, ActionsCreator } from '@umituz/react-native-storage';
|
|
159
|
+
|
|
160
|
+
interface ListState<T> {
|
|
161
|
+
items: T[];
|
|
162
|
+
loading: boolean;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
interface ListActions<T> {
|
|
166
|
+
setItems: (items: T[]) => void;
|
|
167
|
+
addItem: (item: T) => void;
|
|
168
|
+
removeItem: (id: string) => void;
|
|
169
|
+
loadItems: () => Promise<void>;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function createListStore<T>(config: {
|
|
173
|
+
name: string;
|
|
174
|
+
fetcher: () => Promise<T[]>;
|
|
175
|
+
}) {
|
|
176
|
+
return createStore<ListState<T>, ListActions<T>>({
|
|
177
|
+
name: config.name,
|
|
178
|
+
initialState: {
|
|
179
|
+
items: [],
|
|
180
|
+
loading: false,
|
|
181
|
+
},
|
|
182
|
+
actions: (set, get) => ({
|
|
183
|
+
setItems: (items) => set({ items }),
|
|
184
|
+
addItem: (item) => set((state) => ({ items: [...state.items, item] })),
|
|
185
|
+
removeItem: (id) => set((state) => ({
|
|
186
|
+
items: state.items.filter((item) => (item as any).id !== id),
|
|
187
|
+
})),
|
|
188
|
+
loadItems: async () => {
|
|
189
|
+
set({ loading: true });
|
|
190
|
+
const items = await config.fetcher();
|
|
191
|
+
set({ items, loading: false });
|
|
192
|
+
},
|
|
193
|
+
}),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Kullanım
|
|
198
|
+
const userStore = createListStore<User>({
|
|
199
|
+
name: 'users',
|
|
200
|
+
fetcher: () => fetch('/api/users').then(r => r.json()),
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Union Type State
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
type Theme = 'light' | 'dark';
|
|
208
|
+
|
|
209
|
+
interface SettingsState {
|
|
210
|
+
theme: Theme;
|
|
211
|
+
language: 'en' | 'tr';
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const settingsStore = createStore<SettingsState>({
|
|
215
|
+
name: 'settings',
|
|
216
|
+
initialState: {
|
|
217
|
+
theme: 'light',
|
|
218
|
+
language: 'en',
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Discriminated Union
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
type LoadingState = {
|
|
227
|
+
status: 'loading';
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
type SuccessState<T> = {
|
|
231
|
+
status: 'success';
|
|
232
|
+
data: T;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
type ErrorState = {
|
|
236
|
+
status: 'error';
|
|
237
|
+
error: Error;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
type AsyncState<T> = LoadingState | SuccessState<T> | ErrorState;
|
|
241
|
+
|
|
242
|
+
interface DataState {
|
|
243
|
+
user: AsyncState<User>;
|
|
244
|
+
posts: AsyncState<Post[]>;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const dataStore = createStore<DataState>({
|
|
248
|
+
name: 'data',
|
|
249
|
+
initialState: {
|
|
250
|
+
user: { status: 'loading' },
|
|
251
|
+
posts: { status: 'loading' },
|
|
252
|
+
},
|
|
253
|
+
actions: (set) => ({
|
|
254
|
+
loadUser: async () => {
|
|
255
|
+
set({ user: { status: 'loading' } });
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
const user = await fetchUser();
|
|
259
|
+
set({ user: { status: 'success', data: user } });
|
|
260
|
+
} catch (error) {
|
|
261
|
+
set({ user: { status: 'error', error: error as Error } });
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
}),
|
|
265
|
+
});
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Recursive Type
|
|
269
|
+
|
|
270
|
+
```tsx
|
|
271
|
+
interface TreeNode {
|
|
272
|
+
id: string;
|
|
273
|
+
value: any;
|
|
274
|
+
children: TreeNode[];
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
interface TreeState {
|
|
278
|
+
root: TreeNode | null;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const treeStore = createStore<TreeState>({
|
|
282
|
+
name: 'tree',
|
|
283
|
+
initialState: { root: null },
|
|
284
|
+
actions: (set, get) => ({
|
|
285
|
+
setRoot: (root: TreeNode) => set({ root }),
|
|
286
|
+
|
|
287
|
+
findNode: (id: string): TreeNode | null => {
|
|
288
|
+
const { root } = get();
|
|
289
|
+
|
|
290
|
+
const search = (node: TreeNode | null): TreeNode | null => {
|
|
291
|
+
if (!node) return null;
|
|
292
|
+
if (node.id === id) return node;
|
|
293
|
+
|
|
294
|
+
for (const child of node.children) {
|
|
295
|
+
const found = search(child);
|
|
296
|
+
if (found) return found;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return null;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
return search(root);
|
|
303
|
+
},
|
|
304
|
+
}),
|
|
305
|
+
});
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Conditional Type
|
|
309
|
+
|
|
310
|
+
```tsx
|
|
311
|
+
type StoreType<T> = T extends true
|
|
312
|
+
? PersistedStore<T>
|
|
313
|
+
: EphemeralStore<T>;
|
|
314
|
+
|
|
315
|
+
interface PersistedStore<T> {
|
|
316
|
+
getState: () => T;
|
|
317
|
+
setState: (partial: Partial<T>) => void;
|
|
318
|
+
persist: true;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
interface EphemeralStore<T> {
|
|
322
|
+
getState: () => T;
|
|
323
|
+
setState: (partial: Partial<T>) => void;
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Utility Types
|
|
328
|
+
|
|
329
|
+
```tsx
|
|
330
|
+
// DeepPartial - tüm nested özellikler optional
|
|
331
|
+
type DeepPartial<T> = {
|
|
332
|
+
[P in keyof T]?: T[P] extends object
|
|
333
|
+
? DeepPartial<T[P]>
|
|
334
|
+
: T[P];
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// ReadOnly
|
|
338
|
+
type ReadOnlyState<T> = {
|
|
339
|
+
readonly [P in keyof T]: T[P];
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// Optional
|
|
343
|
+
type OptionalState<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
344
|
+
|
|
345
|
+
// Required
|
|
346
|
+
type RequiredState<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Type Guards
|
|
350
|
+
|
|
351
|
+
```tsx
|
|
352
|
+
function isSuccessState<T>(state: AsyncState<T>): state is SuccessState<T> {
|
|
353
|
+
return state.status === 'success';
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function isErrorState<T>(state: AsyncState<T>): state is ErrorState {
|
|
357
|
+
return state.status === 'error';
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function isLoadingState<T>(state: AsyncState<T>): state is LoadingState {
|
|
361
|
+
return state.status === 'loading';
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Kullanım
|
|
365
|
+
const { user } = dataStore.getState();
|
|
366
|
+
|
|
367
|
+
if (isSuccessState(user)) {
|
|
368
|
+
console.log(user.data.name); // Type narrowing: user.data exists
|
|
369
|
+
} else if (isErrorState(user)) {
|
|
370
|
+
console.error(user.error.message); // Type narrowing: user.error exists
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Type Inference
|
|
375
|
+
|
|
376
|
+
### Infer State from Store
|
|
377
|
+
|
|
378
|
+
```tsx
|
|
379
|
+
import { createStore } from '@umituz/react-native-storage';
|
|
380
|
+
|
|
381
|
+
const store = createStore({
|
|
382
|
+
name: 'counter',
|
|
383
|
+
initialState: { count: 0 },
|
|
384
|
+
actions: (set) => ({
|
|
385
|
+
increment: () => set((state) => ({ count: state.count + 1 })),
|
|
386
|
+
}),
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// State tipi otomatik çıkarılır
|
|
390
|
+
type CounterState = ReturnType<typeof store.getState>;
|
|
391
|
+
// { count: number; increment: () => void; }
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Extract Actions
|
|
395
|
+
|
|
396
|
+
```tsx
|
|
397
|
+
type Actions = Pick<CounterState, 'increment'>;
|
|
398
|
+
// { increment: () => void; }
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Extract State
|
|
402
|
+
|
|
403
|
+
```tsx
|
|
404
|
+
type State = Omit<CounterState, 'increment'>;
|
|
405
|
+
// { count: number; }
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## Branded Types
|
|
409
|
+
|
|
410
|
+
```tsx
|
|
411
|
+
type UserId = string & { readonly __brand: unique symbol };
|
|
412
|
+
type PostId = string & { readonly __brand: unique symbol };
|
|
413
|
+
|
|
414
|
+
function createUserId(id: string): UserId {
|
|
415
|
+
return id as UserId;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function createPostId(id: string): PostId {
|
|
419
|
+
return id as PostId;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Yanlış kullanım engellenir
|
|
423
|
+
const userId: UserId = createUserId('user-123');
|
|
424
|
+
const postId: PostId = createPostId('post-456');
|
|
425
|
+
|
|
426
|
+
// postId = userId; // Type error!
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Template Literal Types
|
|
430
|
+
|
|
431
|
+
```tsx
|
|
432
|
+
type StorageKey = `user:${string}` | `post:${string}`;
|
|
433
|
+
|
|
434
|
+
function getStorage<T extends StorageKey>(key: T): any {
|
|
435
|
+
// ...
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const userKey: StorageKey = 'user:123'; // OK
|
|
439
|
+
const postKey: StorageKey = 'post:456'; // OK
|
|
440
|
+
const invalidKey: StorageKey = 'data'; // Type error!
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
## Generic Constraints
|
|
444
|
+
|
|
445
|
+
```tsx
|
|
446
|
+
interface Entity {
|
|
447
|
+
id: string;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
interface EntityState<T extends Entity> {
|
|
451
|
+
items: T[];
|
|
452
|
+
selectedId: string | null;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function createStoreWithEntity<T extends Entity>(config: {
|
|
456
|
+
name: string;
|
|
457
|
+
initialState: EntityState<T>;
|
|
458
|
+
}) {
|
|
459
|
+
return createStore<EntityState<T>>({
|
|
460
|
+
name: config.name,
|
|
461
|
+
initialState: config.initialState,
|
|
462
|
+
actions: (set) => ({
|
|
463
|
+
setSelected: (id: string) => set({ selectedId: id }),
|
|
464
|
+
clearSelected: () => set({ selectedId: null }),
|
|
465
|
+
}),
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Kullanım
|
|
470
|
+
interface User extends Entity {
|
|
471
|
+
name: string;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
interface Product extends Entity {
|
|
475
|
+
price: number;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const userStore = createStoreWithEntity<User>({
|
|
479
|
+
name: 'users',
|
|
480
|
+
initialState: { items: [], selectedId: null },
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
const productStore = createStoreWithEntity<Product>({
|
|
484
|
+
name: 'products',
|
|
485
|
+
initialState: { items: [], selectedId: null },
|
|
486
|
+
});
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
## Mapped Types
|
|
490
|
+
|
|
491
|
+
```tsx
|
|
492
|
+
type Getters<T> = {
|
|
493
|
+
[K in keyof T as `get${Capitalize<K & string>}`]: () => T[K];
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
interface Settings {
|
|
497
|
+
theme: string;
|
|
498
|
+
language: string;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
type SettingsGetters = Getters<Settings>;
|
|
502
|
+
// {
|
|
503
|
+
// getTheme: () => string;
|
|
504
|
+
// getLanguage: () => string;
|
|
505
|
+
// }
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
## Conditional Types with Enums
|
|
509
|
+
|
|
510
|
+
```tsx
|
|
511
|
+
enum Status {
|
|
512
|
+
Loading = 'loading',
|
|
513
|
+
Success = 'success',
|
|
514
|
+
Error = 'error',
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
type StateByStatus<S extends Status> =
|
|
518
|
+
S extends Status.Loading ? { loading: true } :
|
|
519
|
+
S extends Status.Success ? { data: any } :
|
|
520
|
+
S extends Status.Error ? { error: Error } :
|
|
521
|
+
never;
|
|
522
|
+
```
|