barsa ece89de49a Update TypeScript and ESLint configurations for improved type safety and compatibility
- Modified ESLint configuration to support file patterns for TypeScript files.
- Updated TypeScript configurations across multiple applications to use ES2024 and enable composite builds.
- Refactored type inference in domain modules to utilize Zod's infer type for better type safety.
- Enhanced utility functions to handle various data types more robustly, improving overall code quality.
2025-12-12 14:35:19 +09:00

141 lines
3.2 KiB
TypeScript

/**
* Toolkit - Type Helpers
*
* TypeScript utility types and helper functions.
*/
/**
* Make specific properties optional
*/
export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
/**
* Make specific properties required
*/
export type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
/**
* Deep partial (makes all nested properties optional)
*/
export type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]> } : T;
/**
* Extract keys of a certain type
*/
export type KeysOfType<T, U> = {
[K in keyof T]: T[K] extends U ? K : never;
}[keyof T];
/**
* Ensure all keys of a type are present
*/
export function ensureKeys<T extends Record<string, unknown>>(
obj: Partial<T>,
keys: (keyof T)[]
): obj is T {
return keys.every(key => key in obj);
}
/**
* Pick properties by value type
*/
export type PickByValue<T, V> = Pick<
T,
{
[K in keyof T]: T[K] extends V ? K : never;
}[keyof T]
>;
/**
* Safely access nested property
*/
export function getNestedProperty<T>(obj: unknown, path: string, defaultValue?: T): T | undefined {
const keys = path.split(".");
let current: unknown = obj;
const isIndexableObject = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null;
for (const key of keys) {
if (!isIndexableObject(current)) {
return defaultValue;
}
current = current[key];
}
if (current === undefined || current === null) {
return defaultValue;
}
return current as T;
}
// ============================================================================
// Async State Management
// ============================================================================
/**
* Generic async state type for handling loading/success/error states
*/
export type AsyncState<T, E = Error> =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: T }
| { status: "error"; error: E };
/**
* Create an idle state
*/
export function createIdleState<T, E = Error>(): AsyncState<T, E> {
return { status: "idle" };
}
/**
* Create a loading state
*/
export function createLoadingState<T, E = Error>(): AsyncState<T, E> {
return { status: "loading" };
}
/**
* Create a success state with data
*/
export function createSuccessState<T, E = Error>(data: T): AsyncState<T, E> {
return { status: "success", data };
}
/**
* Create an error state
*/
export function createErrorState<T, E = Error>(error: E): AsyncState<T, E> {
return { status: "error", error };
}
/**
* Type guard: check if state is idle
*/
export function isIdle<T, E>(state: AsyncState<T, E>): state is { status: "idle" } {
return state.status === "idle";
}
/**
* Type guard: check if state is loading
*/
export function isLoading<T, E>(state: AsyncState<T, E>): state is { status: "loading" } {
return state.status === "loading";
}
/**
* Type guard: check if state is success
*/
export function isSuccess<T, E>(state: AsyncState<T, E>): state is { status: "success"; data: T } {
return state.status === "success";
}
/**
* Type guard: check if state is error
*/
export function isError<T, E>(state: AsyncState<T, E>): state is { status: "error"; error: E } {
return state.status === "error";
}