Skip to content

Instantly share code, notes, and snippets.

@typomaker
Created February 16, 2021 19:46
Show Gist options
  • Save typomaker/af7241e04a609c9ac6a38e062d1eaa36 to your computer and use it in GitHub Desktop.
Save typomaker/af7241e04a609c9ac6a38e062d1eaa36 to your computer and use it in GitHub Desktop.
Strongly typed query condition as in Yii2 (PHP). [typscript 4.1 literal templates]
export type Path<T> =
T extends Array<infer S> ? Path<S> & string :
(T extends object ? {
[K in keyof T]: T[K] extends Array<any> ? Path.Item<T, K> : K & string | Path.Item<T, K>
}[keyof T] : never)
export namespace Path {
export type Item<T, K extends keyof T> = `${K & string}.${Path<T[K]> & string}`
export type Type<T, Q extends Path<T>> =
T extends Array<infer S> ? (Q extends Path<S> ? Type<S, Q> : never) :
Q extends keyof T ? T[Q] :
Q extends `${infer P}.${infer REST}` ?
P extends keyof T ? (REST extends Path<T[P]> ? Type<T[P], REST> : never)
: never
: never;
}
export type Expression<T> = Expression.Comparison<T> | Expression.Logical<T>
export namespace Expression {
export type Comparison<T> = {
[K in Path<T>]: [("<=" | ">=" | "!=") | ("=" | ">" | "<"), K, Path.Type<T, K>] | ["in" | "!in", K, Path.Type<T, K>[]]
}[Path<T>]
export type Logical<T> = Comparison<T> | [("&&" | "||"), ...Expression<T>[]]
}
type Entity = { id: number, items: [{ name: string }] };
const validPath: Path<Entity> = "items.name"
const typeOfPath: Path.Type<Entity, "id"> = 123
const expression: Expression<Entity> = ["||", ["<=", "items.name", "123"], ["&&", ["<", "items.name", ""], ["!in", "id", [1, 2, 2]]]]
@typomaker
Copy link
Author

typomaker commented Feb 16, 2021

Try here TS Playground!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment