WIP: try to use ts-macros for more implementations
This commit is contained in:
parent
dc6cf5165d
commit
0e2a1e830a
@ -5,9 +5,10 @@
|
|||||||
main: 'index.ts',
|
main: 'index.ts',
|
||||||
scripts: {
|
scripts: {
|
||||||
test: 'echo "Error: no test specified" && exit 1',
|
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',
|
start: 'node build',
|
||||||
go: 'pnpm --sequential "/build|start/"',
|
go: 'pnpm --sequential "/build|start/"',
|
||||||
|
clean: 'rm -r build',
|
||||||
},
|
},
|
||||||
packageManager: 'pnpm',
|
packageManager: 'pnpm',
|
||||||
keywords: [
|
keywords: [
|
||||||
@ -22,9 +23,9 @@
|
|||||||
url: 'https://code.studioinfinity.org/glen/typocomath.git',
|
url: 'https://code.studioinfinity.org/glen/typocomath.git',
|
||||||
},
|
},
|
||||||
devDependencies: {
|
devDependencies: {
|
||||||
'@types/node': '^20.5.0',
|
'@types/node': '^20.6.2',
|
||||||
'source-map': '^0.7.4',
|
'source-map': '^0.7.4',
|
||||||
'ts-macros': '^2.4.0',
|
'ts-macros': '^2.4.1',
|
||||||
'ts-patch': '^3.0.2',
|
'ts-patch': '^3.0.2',
|
||||||
typescript: '^5.1.6',
|
typescript: '^5.1.6',
|
||||||
},
|
},
|
||||||
|
@ -6,14 +6,14 @@ settings:
|
|||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20.5.0
|
specifier: ^20.6.2
|
||||||
version: 20.5.0
|
version: 20.6.2
|
||||||
source-map:
|
source-map:
|
||||||
specifier: ^0.7.4
|
specifier: ^0.7.4
|
||||||
version: 0.7.4
|
version: 0.7.4
|
||||||
ts-macros:
|
ts-macros:
|
||||||
specifier: ^2.4.0
|
specifier: ^2.4.1
|
||||||
version: 2.4.0(typescript@5.1.6)
|
version: 2.4.1(typescript@5.1.6)
|
||||||
ts-patch:
|
ts-patch:
|
||||||
specifier: ^3.0.2
|
specifier: ^3.0.2
|
||||||
version: 3.0.2
|
version: 3.0.2
|
||||||
@ -23,8 +23,8 @@ devDependencies:
|
|||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
/@types/node@20.5.0:
|
/@types/node@20.6.2:
|
||||||
resolution: {integrity: sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==}
|
resolution: {integrity: sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/ansi-regex@5.0.1:
|
/ansi-regex@5.0.1:
|
||||||
@ -158,8 +158,8 @@ packages:
|
|||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/ts-macros@2.4.0(typescript@5.1.6):
|
/ts-macros@2.4.1(typescript@5.1.6):
|
||||||
resolution: {integrity: sha512-HKt4/r1KvtnBKu+RLUPFB4BJk2L4VjN5SlHHJJQSGBq5ycGhYSpgGi6VvbJjYFQscCUXOvSQRyISYVC+FF7Svg==}
|
resolution: {integrity: sha512-DmrftFZ5pgM7dw8ySYcd90wGEfjp7yx9MFw/YyJHNdwKYdUb//lcy/XI/Lvg3LbrGIbjBMEj1rzuc5Kfkzvafg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x
|
typescript: 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2,6 +2,7 @@ import {Complex} from './type.js'
|
|||||||
import type {
|
import type {
|
||||||
Dependencies, Signature, Returns, RealType, AliasOf
|
Dependencies, Signature, Returns, RealType, AliasOf
|
||||||
} from '../interfaces/type.js'
|
} from '../interfaces/type.js'
|
||||||
|
import {$implement} from '../interfaces/type.js'
|
||||||
|
|
||||||
declare module "../interfaces/type" {
|
declare module "../interfaces/type" {
|
||||||
interface Signatures<T> {
|
interface Signatures<T> {
|
||||||
@ -73,7 +74,7 @@ export const divide =
|
|||||||
// and we have to get it straight which operations we need on each type, and
|
// 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<T>, hence the dependency
|
// in fact, we need `addReal` on both T and Complex<T>, hence the dependency
|
||||||
// with a custom name, not generated via Dependencies<...>
|
// with a custom name, not generated via Dependencies<...>
|
||||||
export const sqrt =
|
$implement!('sqrt',
|
||||||
<T>(dep: Dependencies<'equal' | 'conservativeSqrt' | 'unaryMinus', RealType<T>>
|
<T>(dep: Dependencies<'equal' | 'conservativeSqrt' | 'unaryMinus', RealType<T>>
|
||||||
& Dependencies<'zero' | 'complex', T>
|
& Dependencies<'zero' | 'complex', T>
|
||||||
& Dependencies<'absquare' | 're' | 'divideReal', Complex<T>>
|
& Dependencies<'absquare' | 're' | 'divideReal', Complex<T>>
|
||||||
@ -96,6 +97,6 @@ export const sqrt =
|
|||||||
const denomsq = dep.addRR(dep.addRR(myabs, myabs), dep.addRR(r, r))
|
const denomsq = dep.addRR(dep.addRR(myabs, myabs), dep.addRR(r, r))
|
||||||
const denom = dep.conservativeSqrt(denomsq)
|
const denom = dep.conservativeSqrt(denomsq)
|
||||||
return dep.divideReal(num, denom)
|
return dep.divideReal(num, denom)
|
||||||
}
|
})
|
||||||
|
|
||||||
export const conservativeSqrt = sqrt
|
export const conservativeSqrt = sqrt
|
||||||
|
@ -1,86 +1,7 @@
|
|||||||
import type {Dependencies, Signature} from '../interfaces/type.js'
|
import type {Dependencies, Signature} from '../interfaces/type.js'
|
||||||
import {$$typeToString, $$ident, $$escape, $$define} from 'ts-macros'
|
import {$implement} from '../interfaces/type.js'
|
||||||
import * as ts from 'typescript'
|
|
||||||
|
|
||||||
export const square =
|
$implement!('square',
|
||||||
<T>(dep: Dependencies<'multiply', T>): Signature<'square', T> =>
|
<T>(dep: Dependencies<'multiply', T>) => (z:T) => dep.multiply(z, z))
|
||||||
z => dep.multiply(z, z)
|
|
||||||
// z => dep.fooBar(z, z) // fails as desired
|
// z => dep.fooBar(z, z) // fails as desired
|
||||||
// z => dep.multiply(z, 'foo') // still fails as desired
|
// z => dep.multiply(z, 'foo') // still fails as desired
|
||||||
|
|
||||||
// make sure ts-macros is running
|
|
||||||
function $contains<T>(value: T, ...possible: Array<T>) {
|
|
||||||
// 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!<typeof square>();
|
|
||||||
$$typeToString!<
|
|
||||||
<T>(...args: DeepExpand<Parameters<typeof square<T>>>)
|
|
||||||
=> DeepExpand<ReturnType<typeof square<T>>>
|
|
||||||
>()
|
|
||||||
|
|
||||||
type ShallowExpand<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;
|
|
||||||
// Short alias of ShallowExpand for convenience below:
|
|
||||||
type Deps<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;
|
|
||||||
type ExpandedParameters<T extends (...args: any) => any> = {[Index in keyof Parameters<T>]: ShallowExpand<Parameters<T>[Index]>}
|
|
||||||
type ExpandTwice<T extends any[]> = {[Index in keyof T] : ShallowExpand<T[Index]>}
|
|
||||||
type AsArray<T> = T extends any[] ? T : [];
|
|
||||||
type DeepExpand<T> =
|
|
||||||
T extends (...args: any) => any
|
|
||||||
? (...pars: AsArray<DeepExpand<Parameters<T>>>) => DeepExpand<ReturnType<T>> :
|
|
||||||
T extends unknown ? { [K in keyof T]: DeepExpand<T[K]> } : never;
|
|
||||||
|
|
||||||
type Out<T> = ShallowExpand<Dependencies<'multiply', T>>;
|
|
||||||
|
|
||||||
console.log("Deps type is", $$typeToString!<<T>() => Out<T>>())
|
|
||||||
|
|
||||||
type OutB = ExpandTwice<Parameters<typeof square>>;
|
|
||||||
|
|
||||||
console.log("Or perhaps", $$typeToString!<OutB>())
|
|
||||||
|
|
||||||
console.log("Or maybe even", $$typeToString!<
|
|
||||||
<T>(...args: DeepExpand<Parameters<typeof square<T>>>) => DeepExpand<ReturnType<typeof square<T>>>
|
|
||||||
>())
|
|
||||||
|
|
||||||
// Now try to wrap it up in a macro
|
|
||||||
function $exportImpl<Impl>(name: string, expr: Impl) {
|
|
||||||
$$define!(name, expr, false, true); // Final `true` is export
|
|
||||||
$$ident!(name).reflectedType = $$typeToString!<
|
|
||||||
// <T>(...args: DeepExpand<Parameters<Impl<T>>>) => DeepExpand<ReturnType<Impl<T>>> // 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',
|
|
||||||
<T>(dep: Dependencies<'multiply', T>): Signature<'square', T> =>
|
|
||||||
z => dep.multiply(z, z))
|
|
||||||
|
|
||||||
function $reflect<Impl>(expr: Impl) {
|
|
||||||
return $$escape!(() => {
|
|
||||||
const temp: Impl & {reflectedType?: string} = expr;
|
|
||||||
temp.reflectedType = $$typeToString!<
|
|
||||||
// <T>(...args: DeepExpand<Parameters<Impl<T>>>) =>
|
|
||||||
// DeepExpand<ReturnType<Impl<T>>> // 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!(
|
|
||||||
<T>(dep: Dependencies<'multiply', T>): Signature<'square', T> =>
|
|
||||||
z => dep.multiply(z, z))
|
|
||||||
|
|
||||||
export const sqre = $reflect!(
|
|
||||||
<T>(dep: Deps<Dependencies<'multiply', T>>): Signature<'square', T> =>
|
|
||||||
z => dep.multiply(z, z))
|
|
||||||
|
15
src/index.ts
15
src/index.ts
@ -21,17 +21,4 @@ console.log('Result is', myabs)
|
|||||||
|
|
||||||
// Check type of the generic square implementation
|
// Check type of the generic square implementation
|
||||||
console.log('Type of square is', Specifications.generic.square.reflectedType)
|
console.log('Type of square is', Specifications.generic.square.reflectedType)
|
||||||
|
console.log('Type of complex square root is', Specifications.Complex.sqrt.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)
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import {$$typeToString, $$ident, $$define} from 'ts-macros'
|
||||||
|
|
||||||
/*****
|
/*****
|
||||||
* Every typocomath type has some associated types; they need
|
* Every typocomath type has some associated types; they need
|
||||||
* to be published in the following interface. The key is the
|
* to be published in the following interface. The key is the
|
||||||
@ -74,6 +76,13 @@ type SignatureKey<T> = keyof Signatures<T>
|
|||||||
|
|
||||||
export type Signature<Name extends SignatureKey<T>, T> = Signatures<T>[Name]
|
export type Signature<Name extends SignatureKey<T>, T> = Signatures<T>[Name]
|
||||||
export type Returns<Name extends SignatureKey<T>, T> = ReturnType<Signatures<T>[Name]>
|
export type Returns<Name extends SignatureKey<T>, T> = ReturnType<Signatures<T>[Name]>
|
||||||
export type Dependencies<Name extends SignatureKey<T>, T> = {[K in Name]: Signature<K, T>}
|
type Deps<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;
|
||||||
|
export type Dependencies<Name extends SignatureKey<T>, T> = Deps<{[K in Name]: Signature<K, T>}>
|
||||||
|
|
||||||
export type AliasOf<Name extends string, T> = T & {aliasOf?: Name}
|
export type AliasOf<Name extends string, T> = T & {aliasOf?: Name}
|
||||||
|
|
||||||
|
// For defining implementations with type reflection
|
||||||
|
export function $implement<Impl>(name: string, expr: Impl) {
|
||||||
|
$$define!(name, expr, false, true); // Final `true` is export
|
||||||
|
$$ident!(name).reflectedType = $$typeToString!<Impl>();
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2022",
|
"target": "esnext",
|
||||||
"rootDir": "./src",
|
"rootDir": "./src",
|
||||||
"outDir": "./build",
|
"outDir": "./build",
|
||||||
"moduleResolution": "nodenext",
|
"moduleResolution": "nodenext",
|
||||||
|
Loading…
Reference in New Issue
Block a user