Skip to content

Instantly share code, notes, and snippets.

@schicks
Created June 11, 2023 01:22
Show Gist options
  • Save schicks/1bee5b5690ad1c895628798f1cdd6701 to your computer and use it in GitHub Desktop.
Save schicks/1bee5b5690ad1c895628798f1cdd6701 to your computer and use it in GitHub Desktop.
selection types for graphql queries
type Scalar = string | number | boolean | undefined | null
type ScalarsOf<T> = {[Key in keyof T]: T[Key] extends Scalar ? Key : never}[keyof T]
type ObjectsOf<T> = {[Key in keyof T]: T[Key] extends Scalar ? never : Key}[keyof T]
type Simplify<T> = T extends Function ? T : {[K in keyof T]: Simplify<T[K]>};
type ValuableKeys<T> = {[Key in keyof T]: T[Key] extends never ? never : Key}[keyof T]
type Nevertheless<T> = T extends {} ? {[K in ValuableKeys<T>]: Nevertheless<T[K]>} : T
type CompleteSelector<T> = {[Key in ScalarsOf<T>]: true} & {
[Key in ObjectsOf<T>]: T[Key] extends (infer U)[] ? CompleteSelector<U> : CompleteSelector<T[Key]>
}
type Selector<S, T> = CompleteSelector<T> extends S ? S & {__resultType: SelectionResult<S, T>} : never // throw away invalid selectors
type Selected<S, T> = T extends Scalar
? T
: T extends (infer U)[]
? SelectionResult<S, U>[]
: SelectionResult<S, T>
type SelectionResult<S, T> = CompleteSelector<T> extends S ? {
[Key in keyof S]: Key extends keyof T
? Selected<S[Key], T[Key]>
: never // throw away impossible keys
} : never // throw away invalid selectors
const s = <T>() => <S>(s: S): Selector<S, T> => s as any
type Infer<S extends {__resultType: any}> = Simplify<S['__resultType']>
type User = {
id: string
org: Organization
}
type Organization = {
id: string
leader: User
second: User
members: User[]
}
type Query = {
getUser: User
}
const q = s<Query>()
const result = q({
getUser: {
id: true,
org: {
leader: {
id: true
},
second: {
id: true
},
members: {
id: true
}
}
}
})
type Result = Infer<typeof result>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment