diff --git a/src/generic/arithmetic.ts b/src/generic/arithmetic.ts index 5e6fc7e..a61946f 100644 --- a/src/generic/arithmetic.ts +++ b/src/generic/arithmetic.ts @@ -1,5 +1,6 @@ import type {Dependencies, Signature} from '../interfaces/type.js' -import {$$typeToString} from 'ts-macros' +import {$$typeToString, $$ts, $$define, $$raw, $$ident, $$escape} from 'ts-macros' +import * as ts from 'typescript' export const square = (dep: Dependencies<'multiply', T>): Signature<'square', T> => @@ -19,15 +20,23 @@ console.log($contains!(searchItem, "erwin", "tj")); // Transpiles to: console.log(false); // OK, record the type of square: -square.reflectedType = $$typeToString!(); +square.reflectedType = //$$typeToString!(); + $$typeToString!< + (...args: DeepExpand>>) + => DeepExpand>> + >() type ShallowExpand = T extends unknown ? { [K in keyof T]: T[K] } : never; +// Short alias of ShallowExpand for convenience below: +type Deps = T extends unknown ? { [K in keyof T]: T[K] } : never; type ExpandedParameters any> = {[Index in keyof Parameters]: ShallowExpand[Index]>} type ExpandTwice = {[Index in keyof T] : ShallowExpand} type AsArray = T extends any[] ? T : []; type DeepExpand = - T extends (...args: any) => any ? (...pars: AsArray>>) => DeepExpand> : + T extends (...args: any) => any + ? (...pars: AsArray>>) => DeepExpand> : T extends unknown ? { [K in keyof T]: DeepExpand } : never; + type Out = ShallowExpand>; console.log("Deps type is", $$typeToString!<() => Out>()) @@ -39,3 +48,52 @@ console.log("Or perhaps", $$typeToString!()) console.log("Or maybe even", $$typeToString!< (...args: DeepExpand>>) => DeepExpand>> >()) + +// Now try to wrap it up in a macro + +// From the creator of ts-macros; temporary until next release +function $export(name: string, value: unknown) { + $$raw!((ctx, name: ts.Expression, value: ts.Expression) => { + if (!ctx.ts.isStringLiteral(name)) throw ctx.error(name, "Expected a string literal."); + return [ctx.factory.createVariableStatement([ctx.factory.createToken(ctx.ts.SyntaxKind.ExportKeyword)], ctx.factory.createVariableDeclarationList([ + ctx.factory.createVariableDeclaration(name.text, undefined, undefined, value) + ], ctx.ts.NodeFlags.Const))]; + }); +} + +// Obviously we'd prefer the name before the expression, but that won't work +// until the next release +function $exportImpl(expr: Impl, name: string) { + $export!(name, expr); + $$ident!(name).reflectedType = $$typeToString!< + // (...args: DeepExpand>>) => DeepExpand>> // see comment in reflect below. + Impl + >(); +} + +// works but then not visible at import with current ts-macros. +// Author says he will be enhancing this "soon." +$exportImpl!((dep: Dependencies<'multiply', T>): Signature<'square', T> => + z => dep.multiply(z, z), + 'squire') + +function $reflect(expr: Impl) { + return $$escape!(() => { + const temp: Impl & {reflectedType?: string} = expr; + temp.reflectedType = $$typeToString!< + // (...args: DeepExpand>>) => + // DeepExpand>> // error; can't instantiate + // Impl; even if we constrain it to be the type of a generic function, + // that's still not a generic _type_, ugh. + Impl>(); + return temp; + }) as Impl & {reflectedType: string} +} + +export const squre = $reflect!( + (dep: Dependencies<'multiply', T>): Signature<'square', T> => + z => dep.multiply(z, z)) + +export const sqre = $reflect!( + (dep: Deps>): Signature<'square', T> => + z => dep.multiply(z, z)) diff --git a/src/index.ts b/src/index.ts index 81ad66d..79791d0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,3 +21,17 @@ console.log('Result is', myabs) // Check type of the generic square implementation console.log('Type of square is', Specifications.generic.square.reflectedType) + +// Now check the ones that came via macros: + +// Auto-generated export is invisible to TypeScript at the moment, author +// says he will fix: +console.log('Type of squire (auto-exported) is', + // @ts-ignore + Specifications.generic.squire.reflectedType) + +// Via a macro wrapper around the definition, two ways: +console.log('Type of squre (unexpanded) is', + Specifications.generic.squre.reflectedType) +console.log('Type of sqre (expanded) is', + Specifications.generic.sqre.reflectedType)