From 0e2a1e830a799bfab948ab33a6fea85a3427fa75 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Mon, 18 Sep 2023 10:14:11 -0700 Subject: [PATCH] WIP: try to use ts-macros for more implementations --- package.json5 | 7 ++-- pnpm-lock.yaml | 16 ++++---- src/Complex/arithmetic.ts | 5 ++- src/generic/arithmetic.ts | 85 ++------------------------------------- src/index.ts | 15 +------ src/interfaces/type.ts | 11 ++++- tsconfig.json | 2 +- 7 files changed, 30 insertions(+), 111 deletions(-) diff --git a/package.json5 b/package.json5 index 9caaad9..ad38308 100644 --- a/package.json5 +++ b/package.json5 @@ -5,9 +5,10 @@ main: 'index.ts', scripts: { test: 'echo "Error: no test specified" && exit 1', - build: 'tsc && cp etc/package.json build', + build: 'mkdir -p build && cp etc/package.json build && tsc', start: 'node build', go: 'pnpm --sequential "/build|start/"', + clean: 'rm -r build', }, packageManager: 'pnpm', keywords: [ @@ -22,9 +23,9 @@ url: 'https://code.studioinfinity.org/glen/typocomath.git', }, devDependencies: { - '@types/node': '^20.5.0', + '@types/node': '^20.6.2', 'source-map': '^0.7.4', - 'ts-macros': '^2.4.0', + 'ts-macros': '^2.4.1', 'ts-patch': '^3.0.2', typescript: '^5.1.6', }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e828fc9..ab1dcc1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,14 +6,14 @@ settings: devDependencies: '@types/node': - specifier: ^20.5.0 - version: 20.5.0 + specifier: ^20.6.2 + version: 20.6.2 source-map: specifier: ^0.7.4 version: 0.7.4 ts-macros: - specifier: ^2.4.0 - version: 2.4.0(typescript@5.1.6) + specifier: ^2.4.1 + version: 2.4.1(typescript@5.1.6) ts-patch: specifier: ^3.0.2 version: 3.0.2 @@ -23,8 +23,8 @@ devDependencies: packages: - /@types/node@20.5.0: - resolution: {integrity: sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==} + /@types/node@20.6.2: + resolution: {integrity: sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==} dev: true /ansi-regex@5.0.1: @@ -158,8 +158,8 @@ packages: engines: {node: '>= 0.4'} dev: true - /ts-macros@2.4.0(typescript@5.1.6): - resolution: {integrity: sha512-HKt4/r1KvtnBKu+RLUPFB4BJk2L4VjN5SlHHJJQSGBq5ycGhYSpgGi6VvbJjYFQscCUXOvSQRyISYVC+FF7Svg==} + /ts-macros@2.4.1(typescript@5.1.6): + resolution: {integrity: sha512-DmrftFZ5pgM7dw8ySYcd90wGEfjp7yx9MFw/YyJHNdwKYdUb//lcy/XI/Lvg3LbrGIbjBMEj1rzuc5Kfkzvafg==} peerDependencies: typescript: 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x dependencies: diff --git a/src/Complex/arithmetic.ts b/src/Complex/arithmetic.ts index 90c8eab..501d09f 100644 --- a/src/Complex/arithmetic.ts +++ b/src/Complex/arithmetic.ts @@ -2,6 +2,7 @@ import {Complex} from './type.js' import type { Dependencies, Signature, Returns, RealType, AliasOf } from '../interfaces/type.js' +import {$implement} from '../interfaces/type.js' declare module "../interfaces/type" { interface Signatures { @@ -73,7 +74,7 @@ export const divide = // and we have to get it straight which operations we need on each type, and // in fact, we need `addReal` on both T and Complex, hence the dependency // with a custom name, not generated via Dependencies<...> -export const sqrt = +$implement!('sqrt', (dep: Dependencies<'equal' | 'conservativeSqrt' | 'unaryMinus', RealType> & Dependencies<'zero' | 'complex', T> & Dependencies<'absquare' | 're' | 'divideReal', Complex> @@ -96,6 +97,6 @@ export const sqrt = const denomsq = dep.addRR(dep.addRR(myabs, myabs), dep.addRR(r, r)) const denom = dep.conservativeSqrt(denomsq) return dep.divideReal(num, denom) - } + }) export const conservativeSqrt = sqrt diff --git a/src/generic/arithmetic.ts b/src/generic/arithmetic.ts index 720fe57..3903b8d 100644 --- a/src/generic/arithmetic.ts +++ b/src/generic/arithmetic.ts @@ -1,86 +1,7 @@ import type {Dependencies, Signature} from '../interfaces/type.js' -import {$$typeToString, $$ident, $$escape, $$define} from 'ts-macros' -import * as ts from 'typescript' +import {$implement} from '../interfaces/type.js' -export const square = - (dep: Dependencies<'multiply', T>): Signature<'square', T> => - z => dep.multiply(z, z) +$implement!('square', + (dep: Dependencies<'multiply', T>) => (z:T) => dep.multiply(z, z)) // z => dep.fooBar(z, z) // fails as desired // z => dep.multiply(z, 'foo') // still fails as desired - -// make sure ts-macros is running -function $contains(value: T, ...possible: Array) { - // repetition which goes over all the elements in the "possible" array - return +["||", [possible], (item: T) => value === item]; -} - -const searchItem = "needle"; -console.log("In generic arithmetic") -console.log($contains!(searchItem, "erwin", "tj")); -// Transpiles to: console.log(false); - -// OK, record the type of square: -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 unknown ? { [K in keyof T]: DeepExpand } : never; - -type Out = ShallowExpand>; - -console.log("Deps type is", $$typeToString!<() => Out>()) - -type OutB = ExpandTwice>; - -console.log("Or perhaps", $$typeToString!()) - -console.log("Or maybe even", $$typeToString!< - (...args: DeepExpand>>) => DeepExpand>> - >()) - -// Now try to wrap it up in a macro -function $exportImpl(name: string, expr: Impl) { - $$define!(name, expr, false, true); // Final `true` is export - $$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!('squire', - (dep: Dependencies<'multiply', T>): Signature<'square', T> => - z => dep.multiply(z, z)) - -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 a3a5953..4419dee 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,17 +21,4 @@ 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', - // not 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) +console.log('Type of complex square root is', Specifications.Complex.sqrt.reflectedType) diff --git a/src/interfaces/type.ts b/src/interfaces/type.ts index 9fb1163..3728f11 100644 --- a/src/interfaces/type.ts +++ b/src/interfaces/type.ts @@ -1,3 +1,5 @@ +import {$$typeToString, $$ident, $$define} from 'ts-macros' + /***** * Every typocomath type has some associated types; they need * to be published in the following interface. The key is the @@ -74,6 +76,13 @@ type SignatureKey = keyof Signatures export type Signature, T> = Signatures[Name] export type Returns, T> = ReturnType[Name]> -export type Dependencies, T> = {[K in Name]: Signature} +type Deps = T extends unknown ? { [K in keyof T]: T[K] } : never; +export type Dependencies, T> = Deps<{[K in Name]: Signature}> export type AliasOf = T & {aliasOf?: Name} + +// For defining implementations with type reflection +export function $implement(name: string, expr: Impl) { + $$define!(name, expr, false, true); // Final `true` is export + $$ident!(name).reflectedType = $$typeToString!(); +} diff --git a/tsconfig.json b/tsconfig.json index 43f365a..63c0b04 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ES2022", + "target": "esnext", "rootDir": "./src", "outDir": "./build", "moduleResolution": "nodenext",