Skip to content

Instantly share code, notes, and snippets.

@john-h-k
Created July 24, 2024 12:05
Show Gist options
  • Select an option

  • Save john-h-k/56a03a107bf3721816cb5d2979378ef1 to your computer and use it in GitHub Desktop.

Select an option

Save john-h-k/56a03a107bf3721816cb5d2979378ef1 to your computer and use it in GitHub Desktop.
part of my type routing for my A level coursework.
import e = require("express")
import { SetOptional, Split } from "type-fest"
export type AsyncFunction<V> = (...args: never[]) => PromiseLike<V>
export type AsyncReturnType<V> = V extends AsyncFunction<infer U> ? U : V
class QueryStringError extends Error {
inner: Error | null
constructor(inner: Error | null = null) {
super()
this.inner = inner
}
}
class QueryArgumentMissingError extends QueryStringError {
missing: string
constructor(missing: string, inner: Error | null = null) {
super(inner)
this.missing = missing
}
}
class QueryArgumentUnparsableError extends QueryStringError {
name: string
value: string
type: string
constructor(name: string, value: string, type: string, inner: Error | null = null) {
super(inner)
this.name = name
this.value = value
this.type = type
}
}
class QueryParserInvalidError extends QueryStringError {
name: string
unknown: any
constructor(name: string, unknown: any, inner: Error | null = null) {
super(inner)
this.name = name
this.unknown = unknown
}
}
enum QueryArgType {
Date = "date",
Number = "number"
}
type FromQueryTypeName<T> = T extends (infer U)[] ? FromQueryTypeName<U>
: T extends `${infer value}${'?' | ''}` ? QueryTypes[`${keyof QueryTypes}` & value] | (T extends (value & `${QueryArgType}`) ? never : null)
: T;
type QueryResolverType<T> = T extends (...args) => any
? ReturnType<T>
: T extends readonly (infer U)[] | Record<Identifier, infer U> ? U
: FromQueryTypeName<T>;
type QueryTypes = {
number: number,
string: string,
date: Date
}
type Append<T, U extends string> = T extends `${infer value}` ? `${value}?` : {
[K in keyof T as K extends string ? `${K}${U}` : K]: T[K]
}
type ArrayLiteral = [] | ({
[K in keyof readonly (string | number | boolean)[]]: (readonly (string | number | boolean)[])[K]
} & {
readonly 0: string | number | boolean
})
type Identifier = string | number | symbol
type QueryParser = Record<
Identifier,
| ArrayLiteral
| Record<Identifier, string>
| Record<Identifier, number>
| keyof Append<QueryTypes, '?'>
| keyof QueryTypes
| ((...args) => unknown)
>
type ParsedQuery<T extends QueryParser> = {
[K in keyof T]: QueryResolverType<T[K]>
}
export function ParsedQuery<T extends QueryParser>(req: Request, expected: Readonly<T>): ParsedQuery<T> {
const funcMap = {
"number": parseInt,
"date": Date.constructor,
"string": (x) => x
}
const result: Record<string, any> = {}
for (const [k, v] of Object.entries(expected)) {
const raw = req['query'][k] as string
if (raw == null) {
throw new QueryArgumentMissingError(k)
}
try {
if (typeof v == "function") {
result[k] = v(raw)
}
else if (k in funcMap) {
result[k] = raw == null && /\w+?\?/.test(k) ? null : funcMap[k](raw)
}
else {
throw new QueryParserInvalidError(k, v)
}
}
catch (e) {
if (e instanceof(QueryStringError)) {
throw e
}
throw new QueryArgumentUnparsableError(k, raw, v as string, e)
}
}
return result as ParsedQuery<T>
}
type _Shortest<T, U extends any[] = []> = [U] extends [T]
? U
: _Shortest<T, [any, ...U]>
type Shortest<T> = _Shortest<T> extends infer U
? U extends any[]
? Extract<T, U>
: never
: never
type CharSplit<T> = Literal<T> extends T
? T extends `${infer First}${infer Remaining}` ? [First, ...CharSplit<Remaining>] : []
: never
type CharJoin<T> = T extends [infer First, ...infer Remaining]
? First extends string ? `${First}${CharJoin<Remaining>}`
: never : ``
type Delimit<
T,
Prefix extends string,
Postfix extends string,
Optional extends boolean | { prefix: boolean, postfix: boolean } = false
> = [T] extends [`${
Prefix | (Optional extends true | { prefix: true } ? '' : never)}${
infer T}${
Postfix | (Optional extends true | { postfix: true } ? '' : never)}`]
? CharJoin<Shortest<CharSplit<T>>>
: never;
type LiteralType = number | string | boolean
type Literal<T> = T extends string ? string extends T ? never : T : never;
type PathSegment<T = never> = [T] extends [never]
? `/${string}`
: T extends `/${infer Segment}`
? T
: never
export type Path<T = never> = [T] extends [never]
? PathSegment | `${PathSegment}${PathSegment}`
: T extends `/${infer First}${'' | `${infer Remaining}`}`
? T extends `${PathSegment<`/${First}`>}${'' | Path<`/${Remaining}`>}` ? T : never
: never
type PathParamPair<T> = T extends `:${infer id}[${infer type}]${infer opt}`
? [id, type extends keyof QueryTypes ? QueryTypes[type] : never, opt extends '?' ? id : never]
: T extends `:${infer id}${infer opt}` ? [id, string, opt extends '?' ? id : never]
: never
type PathParamsAllRequired<T> = T extends Path<T> ? {
[K in Split<T, '/'>[number] as PathParamPair<K>[0]]: PathParamPair<K>[1]
} : never
export type PathParams<T> = SetOptional<
PathParamsAllRequired<T>,
PathParamPair<Split<T & string, '/'>[number]>[2] & keyof PathParamsAllRequired<T>
> extends infer U ? { [K in keyof U]: U[K] } : never;
type QueryStringPair<T = never> = [T] extends [never]
? `${string}=${string}` | `${string}`
: T extends `${infer Key}=${infer Value}` ? [Key, Value] : T extends `${infer Key}` ? [Key, 'string'] : never
type QueryStringSegment<T = never> = [T] extends [never]
? `${'' | '?' | '&'}${QueryStringPair}`
: T
type QueryStringDelimiter<T> = Delimit<T, '&' | '?', '&' | '#', true>
export type QueryString<T = never> = [T] extends [never]
? QueryStringSegment | QueryStringPair
: T extends string
? T extends `?/${infer _}`
? never
: QueryStringDelimiter<T> extends `${infer First}${'' | `&${infer Remaining}`}`
? T extends '?'
? T : QueryStringDelimiter<T> extends `${QueryStringPair<First> & never | First}${'' | QueryString<Remaining> & never | Remaining}`
? T
: never
: never
: never
type QueryStringAllRequired<T extends string> = {
[K in QueryStringComponents<T>[number] as TypedQueryStringPair<K>[0]]: TypedQueryStringPair<K>[1]
}
type TypedQueryStringPairName<T> = T extends `${infer name}[${infer type}]${infer opt}`
? [name, QueryTypes[type & keyof QueryTypes], opt extends '?' ? name : never]
: never
type UntypedQueryStringPairName<T> = T extends `${infer name}?`
? [name, string, name]
: T extends `${infer name}`
? [name, string, never]
: never
type TypedQueryStringPair<T> = TypedQueryStringPairName<T> extends never
? UntypedQueryStringPairName<T>
: TypedQueryStringPairName<T>
type OnlyAllow<Type, Allowed> = [Allowed] extends Type[keyof Type] ? Type : never
type QueryStringComponents<T extends string> = Split<QueryStringDelimiter<T>, '&'>
export type QueryParams<T = string | Record<string, unknown>> = T extends string
? SetOptional<
QueryStringAllRequired<T>, keyof QueryStringAllRequired<T> & TypedQueryStringPair<QueryStringComponents<T>[number]>[2]
> extends infer U
? {[K in keyof U]: U[K] }
: never
: OnlyAllow<T, QueryTypes[keyof QueryTypes]>
type JSONTypes = {
string: string
date: Date
number: number
array: any[]
boolean: boolean
null: null
}
type PickByType<T, Types> = {
[K in keyof T as T[K] extends Types ? K : never]: T[K]
}
export type JSONSchemaReferences = Record<string, unknown> | undefined //Record<string, JSONSchema<undefined>> | undefined
type JSONSchemaValueType<T> = T extends JSONTypes[keyof JSONTypes]
? keyof PickByType<JSONTypes, T>
: never
type JSONSchemaFromObject<T, References extends JSONSchemaReferences> = {
[K in keyof T]: JSONSchemaValueType<T[K]>
}
function JSONSchema<T>(): JSONSchemaFromObject<T, undefined> {
return undefined!
}
type _JSONSchema<References> = {
[name: string]:
keyof JSONTypes
| keyof References
| `${keyof JSONTypes}[]`
| `${keyof References & string}[]`
//| ProbablyEnum // enums
}
export type JSONSchema<References> = References extends Record<string, _JSONSchema<References>>
? {
[name: string]:
keyof JSONTypes
| keyof References
| `${keyof JSONTypes}[]`
| `${keyof References & string}[]`
| ProbablyEnum // enums
}
: never
type ProbablyEnum = Record<string, string | number>
type MergedJSONTypes<References extends JSONSchemaReferences> = JSONTypes & {
[K in keyof References as K extends string ? K : never]:
References[K] extends JSONSchema<References>
? JSONSchemaType<References[K], References>
: never
}
export type JSONSchemaType<T extends JSONSchema<References>, References extends JSONSchemaReferences> = {
-readonly [K in keyof T]: T[K] extends keyof MergedJSONTypes<References>
? MergedJSONTypes<References>[T[K]]
: T[K] extends `${infer Element & keyof MergedJSONTypes<References>}[]`
? MergedJSONTypes<References>[Element & keyof MergedJSONTypes<References>][]
: T[K] extends ProbablyEnum
? `${keyof T[K] & string}`
: T[K]
}
type NestedBetterIntellisense<T> = {
-readonly [K in keyof T]: NestedBetterIntellisense<T[K]>
}
interface JSONValidator {
<T extends JSONSchema<U>, U extends JSONSchemaReferences>(
json: Record<string, unknown>,
schema: T,
references?: U
): NestedBetterIntellisense<JSONSchemaType<T, U>>
}
export const validator: JSONValidator = null!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment