get template literals working with multiple dependencies

This commit is contained in:
Jos de Jong 2023-09-14 17:42:42 +02:00
parent 722ee05a0a
commit 7dc26ea297
6 changed files with 63 additions and 41 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@
# Typescript # Typescript
# emitted code # emitted code
obj obj
build
# ---> Node # ---> Node
# Logs # Logs

View File

@ -4,7 +4,7 @@
description: 'A hopeful final typescipt-pragmatic mathjs proof-of-concept', description: 'A hopeful final typescipt-pragmatic mathjs proof-of-concept',
main: 'index.ts', main: 'index.ts',
scripts: { scripts: {
test: 'echo "Error: no test specified" && exit 1', go: 'tsc && node build/infer.js'
}, },
keywords: [ keywords: [
'math', 'math',

View File

@ -1,14 +1,17 @@
lockfileVersion: 5.4 lockfileVersion: '6.0'
specifiers: settings:
typescript: ^4.9.3 autoInstallPeers: true
excludeLinksFromLockfile: false
devDependencies: devDependencies:
typescript: 4.9.3 typescript:
specifier: ^4.9.3
version: 4.9.3
packages: packages:
/typescript/4.9.3: /typescript@4.9.3:
resolution: {integrity: sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==} resolution: {integrity: sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==}
engines: {node: '>=4.2.0'} engines: {node: '>=4.2.0'}
hasBin: true hasBin: true

View File

@ -5,53 +5,71 @@
* infer TypeScript interfaces from that using infer in template literal types. * infer TypeScript interfaces from that using infer in template literal types.
*/ */
type T = {} // TODO: how to do generics?
const create = createFactory<{ const create = createFactory<{
number: number number: number
bigint: bigint bigint: bigint
T: T // TODO: how to do generics? string: string
'Complex<T>': unknown // TODO: how to do generics? // T: T // TODO: how to do generics?
// 'Complex<T>': unknown // TODO: how to do generics?
}>() }>()
// TODO: how to pass config? // 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({ const createSquare = create([Multiply, Zero],dep => {
multiply: '(number, number) : number',
// zero: '(number) : number'
},dep => {
return (x: number) => dep.multiply(x, x) return (x: number) => dep.multiply(x, x)
} })
)
// the code works in JS, and works in TS // the code works in JS, and works in TS
const multiply = (a: number, b: number) => a * b 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 console.log('square', square(8)) // 64
function createFactory<BaseTypes extends Record<string, unknown>>() { 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> = type ResolveArguments<S extends string> = S extends ''
S extends '' ? [] : ? []
S extends `${infer T extends K}, ${infer U}` : S extends `${infer Arg extends BaseTypeNames},${infer Tail}`
? [ResolveType<T>, ...ResolveArguments<U>] ? [ResolveType<Arg>, ...ResolveArguments<Tail>]
: S extends `${infer T extends K}` ? [ResolveType<T>] : S extends `${infer Arg extends BaseTypeNames}`
: never; ? [ResolveType<Arg>]
type ResolveFunctionDef<T> =
T extends `${infer Name}(${infer Args}) : ${infer L extends K}`
? (...args: ResolveArguments<Args>) => ResolveType<L>
: never : never
return function create<T extends string, U extends string, V>( type FunctionDefinition<FnType> =
dependencies: { [L in T]: U }, FnType extends Value<infer K>
callback: (deps: { [L in T]: ResolveFunctionDef<U> }) => V ? K extends `${infer Name}(${infer Args})=>${infer ReturnType extends BaseTypeNames}`
? Record<Name, (...args: ResolveArguments<Args>) => ResolveType<ReturnType>>
: never
: never
// 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 return callback
} }
} }

View File

@ -2,6 +2,6 @@
"compilerOptions": { "compilerOptions": {
"target": "ES2022", "target": "ES2022",
"rootDir": "./src", "rootDir": "./src",
"outDir": "./obj" "outDir": "./build"
} }
} }