typomath/src/steps/two.ts

105 lines
3.1 KiB
TypeScript

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 | `${T}, ${Tuple<T>}`
//type TypeTuple = Tuple<TypeName>
type CheckTuple<T> = T extends TypeName
? T
: T extends `${TypeName}, ${infer Rest}`
? CheckTuple<Rest> extends string ? T : false
: false
type CheckDecl<T> = T extends `${infer Args} -> ${TypeName}`
? CheckTuple<Args> extends string ? T : never
: never
function check<T extends string>(d: CheckDecl<T>) {
console.log(d)
}
check('number, bigint -> bigint')
check('bigint -> number')
// check('string -> number') // would be error as desired
class ImpBuilder {
addImp<T extends string, U>(decl: CheckDecl<T>, imp: U) {
return Object.assign(this, {[decl]: imp} as Record<T, U>)
}
// finalize<T extends Record<string, unknown>>(this: T) {
// return overload(this as Omit<T, 'addImp' | 'finalize'>)
// }
finalize() {
delete this.addImp
delete this.finalize
return this
}
}
function fixImps<T extends {addImp: any}>(imps: T): Omit<T, 'addImp'> {
const res = Object.assign({}, imps)
delete res.addImp
return res
}
function overloadImps<T>(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<typeof negateImps, 'finalize'|'addImp'>)
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<typeof addAll, 'finalize'|'addImp'>) // 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<typeof subAddImps, 'finalize'|'addImp'>)
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.')
}
****/