Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
ae2303af7c | |||
9eff2bc265 | |||
af02f1cb29 | |||
da5b2c3467 | |||
770c302342 |
@ -8,3 +8,7 @@ Convenience scripts:
|
||||
* `pnpm build` -- compile the package
|
||||
* `pnpm exec` -- run the compiled code produced by `pnpm build`
|
||||
* `pnpm go` -- both of the above in sequence.
|
||||
|
||||
Important installation note:
|
||||
|
||||
after `pnpm install`, you must execute `npx ts-patch install` to activate the ts-macros compiler plugin.
|
||||
|
@ -24,6 +24,8 @@
|
||||
devDependencies: {
|
||||
'@types/node': '^20.5.0',
|
||||
'source-map': '^0.7.4',
|
||||
'ts-macros': '^2.4.0',
|
||||
'ts-patch': '^3.0.2',
|
||||
typescript: '^5.1.6',
|
||||
},
|
||||
}
|
||||
|
163
pnpm-lock.yaml
163
pnpm-lock.yaml
@ -11,6 +11,12 @@ devDependencies:
|
||||
source-map:
|
||||
specifier: ^0.7.4
|
||||
version: 0.7.4
|
||||
ts-macros:
|
||||
specifier: ^2.4.0
|
||||
version: 2.4.0(typescript@5.1.6)
|
||||
ts-patch:
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.2
|
||||
typescript:
|
||||
specifier: ^5.1.6
|
||||
version: 5.1.6
|
||||
@ -21,13 +27,170 @@ packages:
|
||||
resolution: {integrity: sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==}
|
||||
dev: true
|
||||
|
||||
/ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/ansi-styles@4.3.0:
|
||||
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
dev: true
|
||||
|
||||
/chalk@4.1.2:
|
||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
supports-color: 7.2.0
|
||||
dev: true
|
||||
|
||||
/color-convert@2.0.1:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
dev: true
|
||||
|
||||
/color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
dev: true
|
||||
|
||||
/function-bind@1.1.1:
|
||||
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
|
||||
dev: true
|
||||
|
||||
/global-prefix@3.0.0:
|
||||
resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
ini: 1.3.8
|
||||
kind-of: 6.0.3
|
||||
which: 1.3.1
|
||||
dev: true
|
||||
|
||||
/has-flag@4.0.0:
|
||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/has@1.0.3:
|
||||
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
dependencies:
|
||||
function-bind: 1.1.1
|
||||
dev: true
|
||||
|
||||
/ini@1.3.8:
|
||||
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
|
||||
dev: true
|
||||
|
||||
/is-core-module@2.13.0:
|
||||
resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==}
|
||||
dependencies:
|
||||
has: 1.0.3
|
||||
dev: true
|
||||
|
||||
/isexe@2.0.0:
|
||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||
dev: true
|
||||
|
||||
/kind-of@6.0.3:
|
||||
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/lru-cache@6.0.0:
|
||||
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
yallist: 4.0.0
|
||||
dev: true
|
||||
|
||||
/minimist@1.2.8:
|
||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||
dev: true
|
||||
|
||||
/path-parse@1.0.7:
|
||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||
dev: true
|
||||
|
||||
/resolve@1.22.4:
|
||||
resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
is-core-module: 2.13.0
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
dev: true
|
||||
|
||||
/semver@7.5.4:
|
||||
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
lru-cache: 6.0.0
|
||||
dev: true
|
||||
|
||||
/source-map@0.7.4:
|
||||
resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
|
||||
engines: {node: '>= 8'}
|
||||
dev: true
|
||||
|
||||
/strip-ansi@6.0.1:
|
||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
ansi-regex: 5.0.1
|
||||
dev: true
|
||||
|
||||
/supports-color@7.2.0:
|
||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
has-flag: 4.0.0
|
||||
dev: true
|
||||
|
||||
/supports-preserve-symlinks-flag@1.0.0:
|
||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: true
|
||||
|
||||
/ts-macros@2.4.0(typescript@5.1.6):
|
||||
resolution: {integrity: sha512-HKt4/r1KvtnBKu+RLUPFB4BJk2L4VjN5SlHHJJQSGBq5ycGhYSpgGi6VvbJjYFQscCUXOvSQRyISYVC+FF7Svg==}
|
||||
peerDependencies:
|
||||
typescript: 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x
|
||||
dependencies:
|
||||
typescript: 5.1.6
|
||||
dev: true
|
||||
|
||||
/ts-patch@3.0.2:
|
||||
resolution: {integrity: sha512-iTg8euqiNsNM1VDfOsVIsP0bM4kAVXU38n7TGQSkky7YQX/syh6sDPIRkvSS0HjT8ZOr0pq1h+5Le6jdB3hiJQ==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
global-prefix: 3.0.0
|
||||
minimist: 1.2.8
|
||||
resolve: 1.22.4
|
||||
semver: 7.5.4
|
||||
strip-ansi: 6.0.1
|
||||
dev: true
|
||||
|
||||
/typescript@5.1.6:
|
||||
resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/which@1.3.1:
|
||||
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
dev: true
|
||||
|
||||
/yallist@4.0.0:
|
||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||
dev: true
|
||||
|
@ -1,7 +1,99 @@
|
||||
import type {Dependencies, Signature} from '../interfaces/type.js'
|
||||
import {$$typeToString, $$ts, $$define, $$raw, $$ident, $$escape} from 'ts-macros'
|
||||
import * as ts from 'typescript'
|
||||
|
||||
export const square =
|
||||
<T>(dep: Dependencies<'multiply', T>): Signature<'square', T> =>
|
||||
z => dep.multiply(z, z)
|
||||
// z => dep.fooBar(z, z) // fails as desired
|
||||
// z => dep.multiply(z, 'foo') // 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
|
||||
|
||||
// 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<Impl>(expr: Impl, name: string) {
|
||||
$export!(name, expr);
|
||||
$$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!(<T>(dep: Dependencies<'multiply', T>): Signature<'square', T> =>
|
||||
z => dep.multiply(z, z),
|
||||
'squire')
|
||||
|
||||
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))
|
||||
|
17
src/index.ts
17
src/index.ts
@ -18,3 +18,20 @@ const myabs = quatAbsquare({re: {re: 0, im: 1}, im: {re:2, im: 3}})
|
||||
const typeTest: typeof myabs = 7 // check myabs is just a number
|
||||
|
||||
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)
|
||||
|
@ -3,6 +3,9 @@
|
||||
"target": "ES2022",
|
||||
"rootDir": "./src",
|
||||
"outDir": "./build",
|
||||
"moduleResolution": "nodenext"
|
||||
"moduleResolution": "nodenext",
|
||||
"plugins": [
|
||||
{"transform": "ts-macros" }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user