1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| interface TypeGuard<T> { (value: unknown): value is T; type: string; }
class TypeValidator { static create<T>(guard: (value: unknown) => value is T, typeName: string): TypeGuard<T> { const validator: TypeGuard<T> = guard as TypeGuard<T>; validator.type = typeName; return validator; }
static string = TypeValidator.create<string>( (value: unknown): value is string => typeof value === 'string', 'string' );
static number = TypeValidator.create<number>( (value: unknown): value is number => typeof value === 'number' && !isNaN(value), 'number' );
static boolean = TypeValidator.create<boolean>( (value: unknown): value is boolean => typeof value === 'boolean', 'boolean' );
static array<T>(elementValidator: TypeGuard<T>) { return TypeValidator.create<T[]>( (value: unknown): value is T[] => { return Array.isArray(value) && value.every(item => elementValidator(item)); }, `Array<${elementValidator.type}>` ); }
static object<T extends Record<string, TypeGuard<any>>>( schema: T ): TypeGuard<{ [K in keyof T]: T[K] extends TypeGuard<infer U> ? U : never }> { return TypeValidator.create( (value: unknown): value is any => { if (typeof value !== 'object' || value === null) return false;
for (const [key, validator] of Object.entries(schema)) { if (!(key in value) || !validator((value as any)[key])) { return false; } } return true; }, `Object<${Object.keys(schema).join(', ')}>` ); } }
const UserSchema = TypeValidator.object({ name: TypeValidator.string, age: TypeValidator.number, active: TypeValidator.boolean, tags: TypeValidator.array(TypeValidator.string) });
function validateUser(data: unknown): asserts data is { name: string; age: number; active: boolean; tags: string[]; } { if (!UserSchema(data)) { throw new Error('Invalid user data'); } }
type ApiEndpoint<TRequest, TResponse> = { path: string; method: 'GET' | 'POST' | 'PUT' | 'DELETE'; requestValidator: TypeGuard<TRequest>; responseValidator: TypeGuard<TResponse>; };
function createTypedApi<TRequest, TResponse>( endpoint: Omit<ApiEndpoint<TRequest, TResponse>, 'requestValidator' | 'responseValidator'>, requestValidator: TypeGuard<TRequest>, responseValidator: TypeGuard<TResponse> ): ApiEndpoint<TRequest, TResponse> { return { ...endpoint, requestValidator, responseValidator }; }
const updateUserEndpoint = createTypedApi( { path: '/api/users/:id', method: 'PUT' }, UserSchema, TypeValidator.object({ success: TypeValidator.boolean }) );
|