/** * Idea: instead of writing TypeScript, and inferring the JS-pocomath signature * from TS that via a TypeScript plugin, we can maybe do this the other way * around: take the JS-pocomath signature as base (and source of truth), and * infer TypeScript interfaces from that using infer in template literal types. */ // TODO: get generics working // TODO: how to pass config? const create = createFactory<{ number: number bigint: bigint string: string any: any }>() // These are our string based interfaces, which we can use both in typed-function and in TypeScript: const Multiply = 'multiply(number,number)=>number' const Square = 'square(number)=>number' const Zero = 'zero(number)=>number' // TODO: turn a generic string like `(T,T)=>T` into a concrete one like `(number,number)=>number` // const MultiplyNumber = ResolveGeneric<'multiply', number> const createSquare = create(Square, [Multiply, Zero], dep => x => dep.multiply(x, x) ) // the code works in JS, and works in TS const multiply = (a: number, b: number) => a * b const zero = (a: number) => 0 const square = createSquare({ multiply, zero }) console.log('square', square(8)) // 64 function createFactory>() { type BaseTypeNames = string & keyof BaseTypes type ResolveType = BaseTypes[TypeName] type Value = K type ResolveArguments = S extends '' ? [] : S extends `${infer Arg extends BaseTypeNames},${infer Tail}` ? [ResolveType, ...ResolveArguments] : S extends `${infer Arg extends BaseTypeNames}` ? [ResolveType] : never type DependencyRecord = FnType extends Value ? K extends `${infer Name}(${infer Args})=>${infer ReturnType extends BaseTypeNames}` ? Record) => ResolveType> : never : never type CreatedFunctionType = FnType extends Value ? K extends `${infer Name}(${infer Args})=>${infer ReturnType extends BaseTypeNames}` ? (...args: ResolveArguments) => ResolveType : never : never // inspired by: https://stackoverflow.com/questions/68391632/infer-type-from-array-literal type DependenciesRecord< Arr extends Array>, Result extends Record = {} > = Arr extends [] ? Result : Arr extends [infer H, ...infer Tail] ? Tail extends Array> ? H extends Value ? DependenciesRecord> : never : never : never return function create[], W extends Value>( signature: W, dependencies: [...Dependencies], callback: (deps: DependenciesRecord<[...Dependencies]>) => CreatedFunctionType ) { console.log('Creating typed-function with', { signature, dependencies }) // TODO: create a typed-function for real return callback } }