Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
54d7d01bfc | |||
b15035bfe6 |
@ -8,7 +8,7 @@ Roadmap:
|
|||||||
2. Use the builder pattern to get add working with its implmentations defined incrementally before producing the final overload. [Didn't quite work the way we wnated, but maybe we can do an alternative later.]
|
2. Use the builder pattern to get add working with its implmentations defined incrementally before producing the final overload. [Didn't quite work the way we wnated, but maybe we can do an alternative later.]
|
||||||
3. Make a version of over.ts, call it util/overload.ts, that takes an array of implementations without redundant type annotation. [DONE]
|
3. Make a version of over.ts, call it util/overload.ts, that takes an array of implementations without redundant type annotation. [DONE]
|
||||||
4. Improve that version of overload with rtti to select the implementation without the implementations having to throw errors. [DONE]
|
4. Improve that version of overload with rtti to select the implementation without the implementations having to throw errors. [DONE]
|
||||||
5. Use the builder pattern to get a single object with both an add and a negate method, with both defined incrementally, working. [DONE]
|
3. Use the builder pattern to get a single object with both an add and a negate method, with both defined incrementally, working.
|
||||||
4. Incorporate a subtract method that works on numbers and bigint by separate definitions but with dependencies on add and negate.
|
4. Incorporate a subtract method that works on numbers and bigint by separate definitions but with dependencies on add and negate.
|
||||||
5. Incorporate a subtract method that works with one generic implementation that works for both number and bigint with dependencies on add and negate.
|
5. Incorporate a subtract method that works with one generic implementation that works for both number and bigint with dependencies on add and negate.
|
||||||
5. Attempt to eliminate redundant specification of implementation signatures.
|
5. Attempt to eliminate redundant specification of implementation signatures.
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
import 'reflect-metadata'
|
|
||||||
import {reflect} from 'typescript-rtti'
|
|
||||||
import {merge, overloadValues} from '../util/overload.js'
|
|
||||||
|
|
||||||
const numImps = {
|
|
||||||
add: [(x: number, y: number) => x + y],
|
|
||||||
negate: [(x: number) => -x]
|
|
||||||
} as const
|
|
||||||
|
|
||||||
const strImps = {
|
|
||||||
add: [(x: string, y: string) => x + ', ' + y],
|
|
||||||
negate: [(x: string) => 'NOT ' + x]
|
|
||||||
} as const
|
|
||||||
|
|
||||||
const merger = merge(numImps)
|
|
||||||
const mathImps = merger.with(strImps).imps()
|
|
||||||
|
|
||||||
const math = overloadValues(mathImps)
|
|
||||||
|
|
||||||
console.log(math.add(1.5, 2.5))
|
|
||||||
console.log(math.add('One and a half', 'Two and a half'))
|
|
||||||
console.log(math.negate(3.5))
|
|
||||||
console.log(math.negate('Three and a half'))
|
|
||||||
|
|
||||||
//@ts-expect-error
|
|
||||||
console.log(math.add(1.5, 'Two and a half'))
|
|
@ -10,8 +10,7 @@ export default function overload<T extends readonly [...any[]]>(
|
|||||||
const impTypes = reflect(callSite).parameters[0].elements
|
const impTypes = reflect(callSite).parameters[0].elements
|
||||||
return <any>((...a: any[]) => {
|
return <any>((...a: any[]) => {
|
||||||
for (let i = 0; i < imps.length; ++i) {
|
for (let i = 0; i < imps.length; ++i) {
|
||||||
const paramTypes = imps[i].functionType.parameters
|
const paramTypes = impTypes[i].type.parameters
|
||||||
|| impTypes[i].type.parameters
|
|
||||||
let match = true
|
let match = true
|
||||||
const haveArgs = a.length
|
const haveArgs = a.length
|
||||||
let onArg = 0
|
let onArg = 0
|
||||||
@ -41,77 +40,3 @@ export default function overload<T extends readonly [...any[]]>(
|
|||||||
+ 'did not match any implementation')
|
+ 'did not match any implementation')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type AVO = Record<string, readonly [...any[]]>
|
|
||||||
|
|
||||||
type MergeArrayValues<L extends AVO, R extends AVO> =
|
|
||||||
Pick<L, Exclude<keyof L, keyof R>>
|
|
||||||
& Pick<R, Exclude<keyof R, keyof L>>
|
|
||||||
& { [P in (keyof L & keyof R)]: [...L[P], ...R[P]] }
|
|
||||||
|
|
||||||
function mergeImps<T extends AVO, U extends AVO>(
|
|
||||||
impT: T, impU: U): MergeArrayValues<T, U> {
|
|
||||||
const dummy = Object.assign({}, impT, impU)
|
|
||||||
const result = {} as AVO
|
|
||||||
for (const key in dummy) {
|
|
||||||
if (key in impT) {
|
|
||||||
if (key in impU) {
|
|
||||||
const k = key as Extract<keyof T & keyof U, string>
|
|
||||||
result[k] = [...impT[k], ...impU[k]]
|
|
||||||
} else {
|
|
||||||
result[key] = impT[key]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result[key] = impU[key]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result as MergeArrayValues<T, U>
|
|
||||||
}
|
|
||||||
|
|
||||||
class ImpMerger<T extends AVO> {
|
|
||||||
implementations: T
|
|
||||||
constructor(imps: T) {
|
|
||||||
this.implementations = imps
|
|
||||||
}
|
|
||||||
with<U extends AVO>(
|
|
||||||
moreImps: U, callSite?: CallSite): ImpMerger<MergeArrayValues<T,U>> {
|
|
||||||
const Utype = reflect(callSite).parameters[0]
|
|
||||||
// Annotate the implementations with their RTTI while we have it
|
|
||||||
for (const [key, imps] of Object.entries(moreImps)) {
|
|
||||||
if (!(imps[0].functionType)) {
|
|
||||||
const tuple = Utype.members.find(m => m.name === key)
|
|
||||||
for (let i = 0; i < imps.length; ++i) {
|
|
||||||
imps[i].functionType = tuple.type.elements[i].type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new ImpMerger(mergeImps<T,U>(this.implementations, moreImps))
|
|
||||||
}
|
|
||||||
imps(): T {
|
|
||||||
return this.implementations
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function merge<T extends AVO>(impsObject: T, callSite?: CallSite) {
|
|
||||||
const Ttype = reflect(callSite).parameters[0]
|
|
||||||
// Annotate the implementations with their RTTI while we have it
|
|
||||||
for (const [key, imps] of Object.entries(impsObject)) {
|
|
||||||
if (!(imps[0].functionType)) {
|
|
||||||
const tuple = Ttype.members.find(m => m.name === key)
|
|
||||||
for (let i = 0; i < imps.length; ++i) {
|
|
||||||
imps[i].functionType = tuple.type.elements[i].type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new ImpMerger(impsObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
type OverloadedValues<T extends AVO> = {
|
|
||||||
[P in keyof T]: UnionToIntersection<T[P][number]>}
|
|
||||||
|
|
||||||
function overloadValues<T extends AVO>(impObject: T) : OverloadedValues<T> {
|
|
||||||
return Object.fromEntries(Object.entries(impObject).map(
|
|
||||||
([k, v]) => [k, overload(v)])) as OverloadedValues<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
export {merge, mergeImps, overloadValues}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user