Skip to content

Instantly share code, notes, and snippets.

@WoLfulus
Created February 23, 2023 01:45
Show Gist options
  • Save WoLfulus/99dc7fa1053a52b35ecf3b95d789b94a to your computer and use it in GitHub Desktop.
Save WoLfulus/99dc7fa1053a52b35ecf3b95d789b94a to your computer and use it in GitHub Desktop.
TypeScript build/compilation-time if/then/else blocks
// Utilities
declare const TAG: unique symbol;
type TAG = typeof TAG;
export type Tagged<TagSymbol extends symbol> = {
readonly [TAG]: TagSymbol;
};
export type WithTag<TagSymbol extends symbol, Target> = Tagged<TagSymbol> &
Target;
// PoC
declare const EitherTag: unique symbol;
type EitherTag = typeof EitherTag;
export type Either<T, F> = WithTag<
EitherTag,
{
left: T;
right: F;
}
>;
declare const ElseTag: unique symbol;
type ElseTag = typeof ElseTag;
export type Else = WithTag<ElseTag, "else">;
export type Then<
True extends [any],
// @ts-ignore
E extends Else | undefined = undefined,
False extends [any] | undefined = undefined
> = Either<
True extends [infer TV] ? TV : True,
False extends [infer FV] ? FV : False
>;
export type If<
Statement extends boolean,
ThenBlock,
ElseBlock = undefined
> = ThenBlock extends Either<infer T, infer F> // If an either block
? Statement extends true
? T
: F
: ThenBlock extends Then<
infer ThenTrue,
// @ts-ignore
infer ThenElse,
infer ThenFalse
> // If a then block
? Statement extends true
? ThenTrue
: ThenFalse
: Statement extends true
? ThenBlock
: ElseBlock;
// Usage
type IsUpperCase<S extends string> = S extends Uppercase<S> ? Uppercase<S> extends S ? true: false: false;
type IUC<X extends string> =
If<IsUpperCase<X>, Then<[
`"${X}" is uppercased`
], Else, [
`"${X}" is not uppercased`
]>>;
type A = IUC<"I'm not uppercased">;
type B = IUC<"BUT I AM">;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment