get template literals working with multiple dependencies
This commit is contained in:
parent
722ee05a0a
commit
7dc26ea297
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@
|
||||
# Typescript
|
||||
# emitted code
|
||||
obj
|
||||
build
|
||||
|
||||
# ---> Node
|
||||
# Logs
|
||||
|
@ -1,3 +1,3 @@
|
||||
# typocomath
|
||||
|
||||
A final (?) prototype for a refactor of mathjs, culminating the picomath, pocomath, typomath series. Provides an extensible core with "fuzzy" types for its operations, that can at any time generate exact .d.ts file for its current state.
|
||||
A final (?) prototype for a refactor of mathjs, culminating the picomath, pocomath, typomath series. Provides an extensible core with "fuzzy" types for its operations, that can at any time generate exact .d.ts file for its current state.
|
||||
|
@ -4,7 +4,7 @@
|
||||
description: 'A hopeful final typescipt-pragmatic mathjs proof-of-concept',
|
||||
main: 'index.ts',
|
||||
scripts: {
|
||||
test: 'echo "Error: no test specified" && exit 1',
|
||||
go: 'tsc && node build/infer.js'
|
||||
},
|
||||
keywords: [
|
||||
'math',
|
||||
|
@ -1,14 +1,17 @@
|
||||
lockfileVersion: 5.4
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
specifiers:
|
||||
typescript: ^4.9.3
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
devDependencies:
|
||||
typescript: 4.9.3
|
||||
typescript:
|
||||
specifier: ^4.9.3
|
||||
version: 4.9.3
|
||||
|
||||
packages:
|
||||
|
||||
/typescript/4.9.3:
|
||||
/typescript@4.9.3:
|
||||
resolution: {integrity: sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==}
|
||||
engines: {node: '>=4.2.0'}
|
||||
hasBin: true
|
||||
|
84
src/infer.ts
84
src/infer.ts
@ -5,53 +5,71 @@
|
||||
* infer TypeScript interfaces from that using infer in template literal types.
|
||||
*/
|
||||
|
||||
type T = {} // TODO: how to do generics?
|
||||
|
||||
const create = createFactory<{
|
||||
number: number
|
||||
bigint: bigint
|
||||
T: T // TODO: how to do generics?
|
||||
'Complex<T>': unknown // TODO: how to do generics?
|
||||
number: number
|
||||
bigint: bigint
|
||||
string: string
|
||||
// T: T // TODO: how to do generics?
|
||||
// 'Complex<T>': unknown // TODO: how to do generics?
|
||||
}>()
|
||||
|
||||
|
||||
// TODO: how to pass config?
|
||||
// FIXME: multiple signatures do not work
|
||||
// These are the interfaces:
|
||||
const Multiply = 'multiply(number,number)=>number'
|
||||
const Zero = 'zero(number)=>number'
|
||||
|
||||
const createSquare = create({
|
||||
multiply: '(number, number) : number',
|
||||
// zero: '(number) : number'
|
||||
},dep => {
|
||||
return (x: number) => dep.multiply(x, x)
|
||||
}
|
||||
)
|
||||
const createSquare = create([Multiply, Zero],dep => {
|
||||
return (x: number) => dep.multiply(x, x)
|
||||
})
|
||||
|
||||
// the code works in JS, and works in TS
|
||||
const multiply = (a: number, b: number) => a * b
|
||||
const square = createSquare({ multiply })
|
||||
const zero = (a: number) => 0
|
||||
const square = createSquare({ multiply, zero })
|
||||
console.log('square', square(8)) // 64
|
||||
|
||||
function createFactory<BaseTypes extends Record<string, unknown>>() {
|
||||
type K = string & keyof BaseTypes
|
||||
type BaseTypeNames = string & keyof BaseTypes
|
||||
type ResolveType<TypeName extends BaseTypeNames> = BaseTypes[TypeName]
|
||||
|
||||
type ResolveType<T extends K> = BaseTypes[T]
|
||||
type Value<K> = K
|
||||
|
||||
type ResolveArguments<S extends string> =
|
||||
S extends '' ? [] :
|
||||
S extends `${infer T extends K}, ${infer U}`
|
||||
? [ResolveType<T>, ...ResolveArguments<U>]
|
||||
: S extends `${infer T extends K}` ? [ResolveType<T>]
|
||||
: never;
|
||||
type ResolveArguments<S extends string> = S extends ''
|
||||
? []
|
||||
: S extends `${infer Arg extends BaseTypeNames},${infer Tail}`
|
||||
? [ResolveType<Arg>, ...ResolveArguments<Tail>]
|
||||
: S extends `${infer Arg extends BaseTypeNames}`
|
||||
? [ResolveType<Arg>]
|
||||
: never
|
||||
|
||||
type ResolveFunctionDef<T> =
|
||||
T extends `${infer Name}(${infer Args}) : ${infer L extends K}`
|
||||
? (...args: ResolveArguments<Args>) => ResolveType<L>
|
||||
: never
|
||||
type FunctionDefinition<FnType> =
|
||||
FnType extends Value<infer K>
|
||||
? K extends `${infer Name}(${infer Args})=>${infer ReturnType extends BaseTypeNames}`
|
||||
? Record<Name, (...args: ResolveArguments<Args>) => ResolveType<ReturnType>>
|
||||
: never
|
||||
: never
|
||||
|
||||
return function create<T extends string, U extends string, V>(
|
||||
dependencies: { [L in T]: U },
|
||||
callback: (deps: { [L in T]: ResolveFunctionDef<U> }) => V
|
||||
) {
|
||||
return callback
|
||||
}
|
||||
// inspired by: https://stackoverflow.com/questions/68391632/infer-type-from-array-literal
|
||||
type DepRecord<
|
||||
Arr extends Array<Value<any>>,
|
||||
Result extends Record<string, any> = {}
|
||||
> = Arr extends []
|
||||
? Result
|
||||
: Arr extends [infer H, ...infer Tail]
|
||||
? Tail extends Array<Value<any>>
|
||||
? H extends Value<any>
|
||||
? DepRecord<Tail, Result & FunctionDefinition<H>>
|
||||
: never
|
||||
: never
|
||||
: never
|
||||
|
||||
return function create<K extends string, Dependencies extends Value<K>[], W>(
|
||||
dependencies: [...Dependencies],
|
||||
callback: (deps: DepRecord<[...Dependencies]>) => W
|
||||
) {
|
||||
console.log('Creating typed-function with dependencies:', dependencies)
|
||||
// TODO: create a typed-function for real
|
||||
return callback
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,6 @@
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"rootDir": "./src",
|
||||
"outDir": "./obj"
|
||||
"outDir": "./build"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user