Compare commits

...

2 Commits

Author SHA1 Message Date
Glen Whitney fafc747be5 feat: add more type functions (FAIL: type recursion) 2022-12-27 11:09:30 -05:00
Glen Whitney 40d05045fc refactor: Put all implementations in a single generic
This change eases type inference of return types.
2022-12-27 10:40:30 -05:00
6 changed files with 59 additions and 21 deletions

View File

@ -1,8 +1,9 @@
import {ForType} from '../core/Dispatcher.js'
import * as Complex from './native.js'
import {Complex_type, typeImps} from './type.js'
export {Complex}
export const Complex_bundle = Object.assign({Complex_type}, typeImps())
declare module "../core/Dispatcher" {
interface ImplementationTypes extends ForType<'Complex', typeof Complex> {}
interface ImplementationTypes<T> extends
ForType<'Complex', ReturnType<typeof typeImps<T>>> {}
}

View File

@ -17,6 +17,16 @@ export const Complex_type = {
}
}
export const complex_unary = <T>(dep: Dependency<'zero', [T]>) =>
(t: T) => ({re: t, im: dep.zero(t)})
export const complex_binary = <T>(t: T, u: T) => ({re: t, im: u})
export const typeImps = <T>() => ({
complex_unary: (dep: Dependency<'zero', [T]>) =>
(t: T) => ({re: t, im: dep.zero(t)}),
complex_binary: (t: T, u: T) => ({re: t, im: u}),
zero: (dep: Dependency<'zero', [T]>) =>
(z: Complex<T>) => ({re: dep.zero(z.re), im: dep.zero(z.im)}),
one: (dep: Dependency<'zero' | 'one', [T]>) =>
(z: Complex<T>) => ({re: dep.one(z.re), re: dep.zero(z.im)}),
nan: (dep: Dependency<'nan', [T]>) =>
(z: Complex<T>) => ({re: dep.nan(z.re), im: dep.nan(z.im)}),
re: (dep: Dependency<'re', [T]>) =>
(z: Complex<T>) => dep.re(z.re)
})

View File

@ -11,14 +11,15 @@ type TypeName = string
type Parameter = TypeName
type Signature = Parameter[]
export interface ImplementationTypes {}
export interface ImplementationTypes<T> {}
export type typeOfDependency = {typeOf: (x: unknown) => TypeName}
// Helper for collecting implementations
// (Really just suffixes the type name onto the keys of exports)
export type ForType<T extends string, Exports> = keyof Exports extends string
? {[K in keyof Exports as `${K}_${T}`]: Exports[K]}
: never
export type ForType<Suffix extends string, Exports> =
keyof Exports extends string
? {[K in keyof Exports as `${K}_${Suffix}`]: Exports[K]}
: never
//dummy implementation for now
export function joinTypes(a: TypeName, b: TypeName) {
@ -37,6 +38,18 @@ type FinalShape<FuncType> =
type BeginsWith<Name extends string> = `${Name}${string}`
type ImpNames = keyof ImplementationTypes<unknown>
type MatchingParams<Name extends string, Params extends unknown[], T> =
{[K in ImpNames]: K extends BeginsWith<Name>
? FinalShape<ImplementationTypes<T>[K]> extends (...args: Params) => any
? Parameters<FinalShape<ImplementationTypes<T>[K]>>
: never
: never}[ImpNames]
export type BestType<Name extends string, Params extends unknown[]> =
Params extends MatchingParams<Name, Params, infer T> ? T : unknown
type DependencyTypes<Ob, Name extends string, Params extends unknown[]> =
{[K in keyof Ob]: K extends BeginsWith<Name>
? FinalShape<Ob[K]> extends (...args: Params) => any
@ -46,7 +59,7 @@ type DependencyTypes<Ob, Name extends string, Params extends unknown[]> =
export type Dependency<Name extends string, Params extends unknown[]> =
{[N in Name]:
DependencyTypes<ImplementationTypes, N, Params>[keyof ImplementationTypes]}
DependencyTypes<ImplementationTypes<BestType<N, Params>>, N, Params>[ImpNames]}
// Now types used in the Dispatcher class itself

View File

@ -1,8 +1,13 @@
import {ForType} from '../core/Dispatcher.js'
import * as numbers from './native.js'
import {number_type, typeImps} from './type.js'
import {arithmeticImps} from './arithmetic.js'
export {numbers}
export const numbers_bundle =
Object.assign({number_type}, typeImps(), arithmeticImps())
declare module "../core/Dispatcher" {
interface ImplementationTypes extends ForType<'numbers', typeof numbers> {}
interface ImplementationTypes<T> extends
ForType<'numbers', ReturnType<typeof typeImps<T>>> {}
interface ImplementationTypes<T> extends
ForType<'numbers', ReturnType<typeof arithmeticImps<T>>> {}
}

View File

@ -1,12 +1,15 @@
import {configDependency} from '../core/Config.js'
import {Dependency} from '../core/Dispatcher.js'
export const add = (a: number, b: number) => a + b
export const unaryMinus = (a: number) => -a
export const subtract = (a: number, b: number) => a - b
export const multiply = (a: number, b: number) => a * b
export const divide = (a: number, b: number) => a / b
export const sqrt =
const unaryMinus = (a: number) => -a
export const arithmeticImps = <T>() => ({
add: (a: number, b: number) => a + b,
unaryMinus,
subtract: (a: number, b: number) => a - b,
multiply: (a: number, b: number) => a * b,
divide: (a: number, b: number) => a / b,
sqrt:
(dep: configDependency
& Dependency<'complex', [number, number]>) => {
if (dep.config.predictable || !dep.complex) {
@ -18,3 +21,4 @@ export const sqrt =
return dep.complex(0, Math.sqrt(unaryMinus(a)))
}
}
})

View File

@ -4,4 +4,9 @@ export const number_type = {
from: {string: s => +s}
}
export const zero = (a: number) => 0
export const typeImps = <T>() => ({
zero: (a: number) => 0,
one: (a: number) => 1,
nan: (a: number) => NaN,
re: (a: number) => a
})