type Trim<S> = S extends (` ${infer V}` | `${infer V} ` |`${infer V}`) ? V : never;
type Templ<S> = S extends `${string}{{${infer Prop extends string}}}${infer Right}` ? {[k in Trim<Prop>]: string} & Templ<Right> : {};
function templ<T extends string, V = Templ<T>>(str:T, sub:V){
Some typescript magic to make named arguments a reality... Sort of.
type Fn = (arg: any) => any;
// oh boy don't do this
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
// Tuplify code from:
//https://stackoverflow.com/questions/55127004/how-to-transform-union-type-to-tuple-type
// oh boy don't do this
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
type LastOf<T> = UnionToIntersection<T extends any ? () => T : never> extends () => (infer R) ? R : never
// TS4.1+
I've been wanting to implement a real regex engine in TypeScript types, but alas its a lot of work. So Instead I implemented a simple one from Nick Drane
// https://nickdrane.com/build-your-own-regex/
// https://github.com/nadrane/build-your-own-regex
type Empty = '' | null | undefined;
type Eq<L, R, T=true, F=false> = L extends R ? R extends L ? T : F : F;
Thought I would write a CSS Parser in TypeScript Types. Like all these exercises there is no practical application, but I thought they are fun.
Maybe there is something to learn, cause I did.
type WS = ' ' | '\n' | '\t';
type Trim<T> = T extends (`${WS}${infer V}` | `${infer V}${WS}`) ? Trim<V> : T;
Something dumb to do for dumb reasons. This isn't a good idea, or well implemented. But I learned a few things, and thought I'd share.
//These types parse XML. With some caveats.
// - depends on what you mean by parsing.
// - practical applications.
//
// Bugs:
// - Will parse malformed documents, particularly root elements.
I was really unhappy with my first attempt an XML Parser in TypeScript types, it really didn't work. So I started over, and this one pretty much works. If you don't count being super strict as works. It'd be pretty easy to fix its lax ness. Also handling name spaces would be a bit of work.
type ALPHA = 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j'|'k'|'l'|'m'|'n'|'o'|'p'|'q'|'r'|'s'|'t'|'u'|'v'|'w'|'x'|'y'|'z';
type Alpha = ALPHA | Uppercase<ALPHA>;
type NUMBS = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
type Special = '_' | '-' | '.';
Have you ever wanted a truly terrible XML Parser. Not only incomplete but slow and difficult to understand. Well here you go.
type Trim<T> = T extends (` ${infer V}` | `${infer V} ` | `${infer V}\n`) ? Trim<V>: T;
type ParseAttrs<T extends string, R extends {} = {}> =
Trim<T> extends '' ? R :
T extends `${infer Before} ${infer Key}="${infer Value}"${infer Rest}`?
ParseAttrs<Trim<Before>, ParseAttrs<Trim<Rest>, R & { [k in Key]:Value}>> :
So properties files are useful sometimes. They can story configurations and stuff. So parsing them is not hard, but multi-line values and other gotchas are well -- a little tricky.
type Join<T, D extends string =' ', Ret extends string = ''> = T extends [infer First, ...infer Rest] ?
First extends string ? Join<Rest, D, Ret extends '' ? First : `${Ret}${D}${First}`> : Join<Rest,D,Ret> : Ret ;
type ParseLine<T, Ret extends [string,string] = ['','']> =
T extends '' ? Ret :
T extends (`${infer Left}\\n${infer Rest}` ) ?
Let's face it working with strings in TypeScript types isn't always obvious, so I thought I would write some little utilities to make that easier. These are the ones that come to mind.
type UpperFirst<T> = T extends `${infer First}${infer Rest}` ? `${Capitalize<First>}${Rest}` : T;
type ReplaceAll<T,Word extends string, With extends string> =
T extends `${infer Left}${Word}${infer Right}` ?
`${Left}${With}${ReplaceAll<Right, Word, With>}` :