refactor: Put all implementations in a single generic

This change eases type inference of return types.
This commit is contained in:
Glen Whitney 2022-12-27 10:40:30 -05:00
parent 3fa216d1f4
commit 40d05045fc
6 changed files with 48 additions and 21 deletions

View File

@ -1,8 +1,9 @@
import {ForType} from '../core/Dispatcher.js' 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" { 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,8 @@ export const Complex_type = {
} }
} }
export const complex_unary = <T>(dep: Dependency<'zero', [T]>) => export const typeImps = <T>() => ({
(t: T) => ({re: t, im: dep.zero(t)}) complex_unary: (dep: Dependency<'zero', [T]>) =>
export const complex_binary = <T>(t: T, u: T) => ({re: t, im: u}) (t: T) => ({re: t, im: dep.zero(t)}),
complex_binary: (t: T, u: T) => ({re: t, im: u})
})

View File

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

View File

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

View File

@ -4,4 +4,6 @@ export const number_type = {
from: {string: s => +s} from: {string: s => +s}
} }
export const zero = (a: number) => 0 export const typeImps = <T>() => ({
zero: (a: number) => 0
})