groq-builder
Version:
A **schema-aware**, strongly-typed GROQ query builder. It enables you to build GROQ queries using **auto-completion**, **type-checking**, and **runtime validation**.
29 lines (28 loc) • 1.29 kB
TypeScript
/**
* Extracts all deep paths of nested types.
*
* @example
* type Keys = Path<{ a: { b: { c: "C" } } }>;
* // Keys = "a" | "a.b" | "a.b.c"
*/
export type Path<T> = keyof T extends string ? PathImpl2<T> extends infer P ? P extends string | keyof T ? P : keyof T : keyof T : never;
/**
* Extracts the value of a deep path.
*
* @example
* type Val = PathValue<{ a: { b: { c: "C" } } }, "a.b.c">;
* // Val = "C";
*/
export type PathValue<T, P extends Path<T>> = P extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? Rest extends Path<T[Key]> ? PathValue<T[Key], Rest> : never : never : P extends keyof T ? T[P] : never;
/**
* Returns a deeply-flattened type
* @example
* PathEntries<{ a: { b: "C" } }> === { a: { b: "C" }, "a.b": "C" }
*/
export type PathEntries<TResultItem> = {
[P in Path<TResultItem>]: PathValue<TResultItem, P>;
};
type IsAny<T> = unknown extends T ? [keyof T] extends [never] ? false : true : false;
type PathImpl<T, Key extends keyof T> = Key extends string ? IsAny<T[Key]> extends true ? never : T[Key] extends Record<string, any> ? `${Key}.${PathImpl<T[Key], Exclude<keyof T[Key], keyof any[]>> & string}` | `${Key}.${Exclude<keyof T[Key], keyof any[]> & string}` : never : never;
type PathImpl2<T> = PathImpl<T, keyof T> | keyof T;
export {};