Skip to content

Instantly share code, notes, and snippets.

@mio991
Created September 9, 2020 18:23
Show Gist options
  • Save mio991/c54e940e4ae599edec79488d30846db7 to your computer and use it in GitHub Desktop.
Save mio991/c54e940e4ae599edec79488d30846db7 to your computer and use it in GitHub Desktop.
Some Typescript for template descriptions
type Filter<K extends keyof C, C, U> = C[K] extends U & Assignables ? K : never;
type BaseAssignables = string | boolean | number | symbol | undefined | null;
type Assignables = BaseAssignables | BaseAssignables[]
type Context = {
[K in PropertyKey]?: Assignables | ((ev: HTMLElementEventMap[keyof HTMLElementEventMap]) => any);
}
type Binding<T, C extends Context> = {
attributes?: {
[K in keyof T]?: Filter<keyof C, C, T[K]>;
},
events?: {
[K in keyof HTMLElementEventMap]?: Filter<keyof C, C, (ev: HTMLElementEventMap[keyof HTMLElementEventMap]) => any>;
}
}
type Factory<C> = (context: C) => HTMLElement[] | HTMLElement;
function element<K extends keyof HTMLElementTagNameMap, C extends Context>
(tag: K, binding: Binding<HTMLElementTagNameMap[K], C>):
(...children: Factory<Context>[]) =>
Factory<Context> {
return function (...children) {
return function (context) {
return document.createElement(tag);
}
}
}
function div<C extends Context>(binding: Binding<HTMLDivElement, C>) {
return element<"div", C>("div", binding);
}
type test = Binding<{ test: string }, {
test: string;
test1: string[];
test2: number;
}>;
div<{
test: string;
test1: string[];
test2: number;
}>({
attributes: {
className: "test"
}
})()({
test: "lalala"
})
@mio991
Copy link
Author

mio991 commented Sep 9, 2020

So I have some Typescript I want to use to create DOM-Elements easily but I just can't get the Type Inference to do the Correct thing I would be happy for Ideas what I could change.
The End usage should look like this:

const templateFactory = div({})(
    div({})(
        h1({innerText: "title"})()
        h3({innerText: "subtitle"})()
    ),
    div({})(
        p({innerText: "article"})()
    )
)

// templateFactory should have the type: (context:{title:string; subtitle:string; article:string;})=> HTMLDivElement

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment