feat: add example of specifying dependencies and signature with runtime vals

This commit is contained in:
Glen Whitney 2023-08-18 02:40:05 -07:00
parent cc1e66c054
commit ed2ae1b006
6 changed files with 70 additions and 11 deletions

View File

@ -18,6 +18,8 @@
url: 'https://code.studioinfinity.org/glen/typocomath.git', url: 'https://code.studioinfinity.org/glen/typocomath.git',
}, },
devDependencies: { devDependencies: {
'@types/node': '^20.5.0',
'source-map': '^0.7.4',
typescript: '^4.9.3', typescript: '^4.9.3',
}, },
} }

View File

@ -1,14 +1,32 @@
lockfileVersion: 5.4 lockfileVersion: '6.0'
specifiers: settings:
typescript: ^4.9.3 autoInstallPeers: true
excludeLinksFromLockfile: false
devDependencies: devDependencies:
typescript: 4.9.3 '@types/node':
specifier: ^20.5.0
version: 20.5.0
source-map:
specifier: ^0.7.4
version: 0.7.4
typescript:
specifier: ^4.9.3
version: 4.9.3
packages: packages:
/typescript/4.9.3: /@types/node@20.5.0:
resolution: {integrity: sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==}
dev: true
/source-map@0.7.4:
resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
engines: {node: '>= 8'}
dev: true
/typescript@4.9.3:
resolution: {integrity: sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==} resolution: {integrity: sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==}
engines: {node: '>=4.2.0'} engines: {node: '>=4.2.0'}
hasBin: true hasBin: true

View File

@ -1,5 +1,32 @@
import type {Dependencies, Signature} from '../interfaces/type.js' import type {Dependencies, Signature} from '../interfaces/type.js'
export const square = // This stuff would really go in interfaces/type.js or someplace like that
<T>(dep: Dependencies<'multiply', T>): Signature<'square', T> => type Annotate<U> = U & {dependencies?: Record<string, string>, signature?: string}
z => dep.multiply(z, z)
function genericImplementation<Deps extends Record<string, string>, Sig extends string>(
deps: Deps, sig: Sig, impl: <T>(dep: Dependencies<keyof Deps, T>) => Signature<Sig, T>
) {
const rimpl: Annotate<typeof impl> = impl
rimpl.dependencies = deps
rimpl.signature = sig
return rimpl
}
// and of course it would need to be generalized somewhat from the above
// --------------
// Then here for the implementation we would have:
export const square = genericImplementation(
{multiply: 'T'}, 'square', <T>(dep) => z => dep.multiply(z, z)
)
// Note this was previously
// export const square =
// <T>(dep: Dependencies<'multiply', T>): Signature<'square', T> =>
// z => dep.multiply(z, z)
// but then we couldn't get at the dependencies or the signature at runtime. So the point of
// genericImplementation is that it takes literal values for the dependencies and signature,
// from which it deduces the types of the actual dependencies of the implementation and the
// the implementation itself, and then it copies those literal values onto properties of the
// implementation, where they can be accessed at runtime as illustreated in ../index.ts

View File

@ -18,3 +18,14 @@ const myabs = quatAbsquare({re: {re: 0, im: 1}, im: {re:2, im: 3}})
const typeTest: typeof myabs = 7 // check myabs is just a number const typeTest: typeof myabs = 7 // check myabs is just a number
console.log('Result is', myabs) console.log('Result is', myabs)
console.log('Dependencies of square are', Specifications.generic.square.dependencies)
console.log('Signature of square is', Specifications.generic.square.signature)
const realSquare = Specifications.generic.square<number>({multiply: (a,b) => a*b})
console.log('Square of 2.5 is', realSquare(2.5))
// and note the following fail with a type error as desired:
// const fakeSquare = Specifications.generic.square<number>({multiply: (a,b,c) => a*b*c})
// const stringSquare = Specifications.generic.square<string>({multiply: (a,b) => a*b})
// console.log('Square of three is', stringSquare('three'))

View File

@ -68,8 +68,8 @@ export interface Signatures<T> {
type SignatureKey<T> = keyof Signatures<T> type SignatureKey<T> = keyof Signatures<T>
export type Signature<Name extends SignatureKey<T>, T> = Signatures<T>[Name] export type Signature<Name, T> = Signatures<T>[Name & SignatureKey<T>]
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>} export type Dependencies<Name, T> = {[K in Name & SignatureKey<T>]: Signature<K, T>}
export type AliasOf<Name extends string, T> = T & {aliasOf?: Name} export type AliasOf<Name extends string, T> = T & {aliasOf?: Name}

View File

@ -2,6 +2,7 @@
"compilerOptions": { "compilerOptions": {
"target": "ES2022", "target": "ES2022",
"rootDir": "./src", "rootDir": "./src",
"outDir": "./obj" "outDir": "./obj",
"moduleResolution": "nodenext"
} }
} }