Skip to content

Instantly share code, notes, and snippets.

@Lucifier129
Created September 5, 2021 11:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Lucifier129/8c4dbb71770dec8dad6ce0ce7713afed to your computer and use it in GitHub Desktop.
Save Lucifier129/8c4dbb71770dec8dad6ce0ce7713afed to your computer and use it in GitHub Desktop.
conditional union/intersection types
// type utils
type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (
x: infer R
) => any
? R
: never;
type UnionOf<T extends object> = T[keyof T];
type IntersectionOf<T extends object> = UnionToIntersection<UnionOf<T>>;
type TypeMap = {
'|': object;
'&': object;
};
type TypeConfig<T extends TypeMap> = {
[key in keyof T['|'] | keyof T['&']]?: boolean;
};
type UnionTypeOf<T extends TypeMap, U extends TypeConfig<T>> = UnionOf<
{
[key in keyof T['|']]: key extends keyof U
? U[key] extends true
? T['|'][key]
: never
: never;
}
>;
type IntersectionTypeOf<
T extends TypeMap,
U extends TypeConfig<T>
> = IntersectionOf<
{
[key in keyof T['&']]: key extends keyof U
? U[key] extends true
? T['&'][key]
: never
: never;
}
>;
type MergeType<T extends TypeMap, U extends TypeConfig<T>> = IntersectionTypeOf<
T,
U
> &
{
[key in keyof T['|']]: key extends keyof U
? U[key] extends true
? T['|'][key]
: never
: never;
}[keyof T['|']];
// response type
type DefaultValueResponse<T> = {
kind: 'Response.defaultValue';
defaultValue: T;
};
type PendingResponse = {
kind: 'Response.pending';
};
type ErrorResponse = {
kind: 'Response.error';
error: Error;
};
type DataResponse<T> = {
kind: 'Response.data';
data: T;
};
type SnapshotResponse<T> = {
snapshot?: T;
};
type ParamsResponse<T> = {
params?: T;
};
type ResponseUnions<T> = {
defaultValue: DefaultValueResponse<T>;
pending: PendingResponse;
error: ErrorResponse;
data: DataResponse<T>;
};
type ResponseIntersections<T> = {
snapshot: SnapshotResponse<T>;
params: ParamsResponse<T>;
};
type ResponseMap<T> = {
'|': ResponseUnions<T>;
'&': ResponseIntersections<T>;
};
type ResOptions<T> = {
defaultValue?: T;
throwError?: boolean;
snapshot?: boolean;
};
type ResType<T, U extends ResOptions<T> = {}> = MergeType<
ResponseMap<T>,
{
data: true;
params: true;
defaultValue: U extends { defaultValue: T } ? true : false;
pending: U extends { defaultValue: T } ? false : true;
error: U extends { throwError: false } ? false : true;
snapshot: U extends { snapshot: true } ? true : false;
}
>;
type T1 = ResType<number>;
type T2 = ResType<number, { defaultValue: number }>;
type T3 = ResType<number, { defaultValue: number; snapshot: true }>;
type T4 = ResType<
number,
{ defaultValue: number; snapshot: true; throwError: false }
>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment