import { useTypes } from 'over.ts'; const types = { number: (x: unknown): x is number => typeof x === 'number', bigint: (x: unknown): x is bigint => typeof x === 'bigint' } const overload = useTypes(types) type TypeName = keyof typeof types //type Tuple = T | `${T}, ${Tuple}` //type TypeTuple = Tuple type CheckTuple = T extends TypeName ? T : T extends `${TypeName}, ${infer Rest}` ? CheckTuple extends string ? T : false : false type CheckDecl = T extends `${infer Args} -> ${TypeName}` ? CheckTuple extends string ? T : never : never function check(d: CheckDecl) { console.log(d) } check('number, bigint -> bigint') check('bigint -> number') // check('string -> number') // would be error as desired class ImpBuilder { addImp(decl: CheckDecl, imp: U) { return Object.assign(this, {[decl]: imp} as Record) } // finalize>(this: T) { // return overload(this as Omit) // } finalize() { delete this.addImp delete this.finalize return this } } function fixImps(imps: T): Omit { const res = Object.assign({}, imps) delete res.addImp return res } function overloadImps(imps: T) { return overload(imps) } const negateImps = new ImpBuilder() .addImp('number -> number', (a: number) => -a) .addImp('bigint -> bigint', (a: bigint) => -a) const negate = overload(negateImps.finalize() as Omit) console.log('Negation of 5 is', negate(5)) console.log('Negation of 5n is', negate(5n)) const addImps = new ImpBuilder() // imagining this is in some "initialize a proto-bundle" file addImps.addImp('number, number -> number', (a: number, b: number) => a+b) // imagining this line in the `number` file const addAll = addImps.addImp('bigint, bigint -> bigint', (a: bigint, b: bigint) => a+b) // and this is in the `bigint` file const add = overload(addAll.finalize() as Omit) // We wrap everything up elsewhere // This should **NOT** be an error but sadly it is: //@ts-expect-error console.log('Sum of 5 and 7 is', add(5,7)) console.log('Sum of 5n and 7n is', add(5n, 7n)) try { //@ts-expect-error console.log('Mixed sum is', add(5n, 7)) } catch { console.log('Mixed sum errored as expected.') } /***** const addImps = new ImpBuilder() //addImps.addImp('number, number -> number', (a: number, b: number) => a+b) const subAddImps = addImps.addImp('number, number -> number', (a: number, b: number) => a+b).addImp('bigint, bigint -> bigint', (a: bigint, b: bigint) => { console.log('adding bigints') return a+b }) //const finalAddImps = addImps.finalize() const add = overload(subAddImps.finalize() as Omit) console.log('Sum of 5 and 7 is', add(5,7)) console.log('Sum of 5n and 7n is', add(5n, 7n)) try { //@ts-expect-error console.log('Mixed sum is', add(5n, 7)) } catch { console.log('Mixed sum errored as expected.') } ****/