@data-client/rest
Version:
Quickly define typed REST resources and endpoints
57 lines (48 loc) • 1.85 kB
text/typescript
type OnlyOptional<S extends string> =
S extends `${infer K}}?` ? K
: S extends `${infer K}?` ? K
: never;
type OnlyRequired<S extends string> = S extends `${string}?` ? never : S;
/** Parameters for a given path */
export type PathArgs<S extends string> =
PathKeys<S> extends never ?
// unknown is identity for intersection ('&')
unknown
: KeysToArgs<PathKeys<S>>;
/** Computes the union of keys for a path string */
export type PathKeys<S extends string> =
string extends S ? string
: S extends `${infer A}\\${':' | '?' | '+' | '*' | '{' | '}'}${infer B}` ?
PathKeys<A> | PathKeys<B>
: PathSplits<S>;
type PathSplits<S extends string> =
S extends (
`${string}:${infer K}${'/' | ',' | '%' | '&' | '+' | '*' | '{'}${infer R}`
) ?
PathSplits<`:${K}`> | PathSplits<R>
: S extends `${string}:${infer K}:${infer R}` ?
PathSplits<`:${K}`> | PathSplits<`:${R}`>
: S extends `${string}:${infer K}` ? K
: never;
export type KeysToArgs<Key extends string> = {
[K in Key as OnlyOptional<K>]?: string | number;
} & (OnlyRequired<Key> extends never ? unknown
: {
[K in Key as OnlyRequired<K>]: string | number;
});
export type PathArgsAndSearch<S extends string> =
OnlyRequired<PathKeys<S>> extends never ?
Record<string, number | string | boolean> | undefined
: {
[K in PathKeys<S> as OnlyRequired<K>]: string | number;
} & Record<string, number | string>;
/** Removes the last :token */
export type ShortenPath<S extends string> =
string extends S ? string
: S extends `${infer B}:${infer R}` ? TrimColon<`${B}:${ShortenPath<R>}`>
: '';
type TrimColon<S extends string> =
string extends S ? string
: S extends `${infer R}:` ? R
: S;
export type ResourcePath = string; // `${string}:${string}`; TODO: Maybe do this in the future? Seems to hard to understand for now