typocomath/src/Complex/type.ts

59 lines
2.1 KiB
TypeScript

import {
joinTypes, typeOfDependency, Dependency, ImpType, ImpReturns
} from '../core/Dispatcher.js'
export type Complex<T> = {re: T; im: T;}
export type UnderlyingReal<T> =
T extends Complex<infer U> ? UnderlyingReal<U> : T
export const Complex_type = {
test: <T>(dep: {testT: (z: unknown) => z is T}) =>
(z: unknown): z is Complex<T> =>
typeof z === 'object' && 're' in z && 'im' in z
&& dep.testT(z.re) && dep.testT(z.im),
infer: (dep: typeOfDependency) =>
(z: Complex<unknown>) => joinTypes(dep.typeOf(z.re), dep.typeOf(z.im)),
from: {
T: <T>(dep: Dependency<'zero', [T]>) => (t: T) =>
({re: t, im: dep.zero(t)}),
Complex: <U,T>(dep: {convert: (from: U) => T}) =>
(z: Complex<U>) => ({re: dep.convert(z.re), im: dep.convert(z.im)})
}
}
export interface ComplexImpTypes<T> {
complex: (a: T, b?: T) => Complex<T>
zero: T extends Complex<infer R>
? (a: Complex<R>) => Complex<R | ImpReturns<'zero', [R]>> : never
one: T extends Complex<infer R>
? (a: Complex<R>) => Complex<R | ImpReturns<'one' | 'zero', [R]>> : never
nan: T extends Complex<infer R>
? (a: Complex<R>) => Complex<R | ImpReturns<'NaN', [R]>> : never
re: T extends Complex<infer R>
? (a: Complex<R>) => UnderlyingReal<R> : never
}
export const complex_unary =
<T>(dep: Dependency<'zero', [T]>): ImpType<'complex', [T]> =>
t => ({re: t, im: dep.zero(t)})
export const complex_binary = <T>(t: T, u: T): ImpReturns<'complex', [T,T]> =>
({re: t, im: u})
export const zero =
<T>(dep: Dependency<'zero', [T]>): ImpType<'zero', [Complex<T>]> =>
z => complex_binary(dep.zero(z.re), dep.zero(z.im))
export const one =
<T>(dep: Dependency<'zero' | 'one', [T]>): ImpType<'one', [Complex<T>]> =>
z => // Must provide parameter T, else TS narrows to return type of dep.one
complex_binary<T>(dep.one(z.re), dep.zero(z.im))
export const nan =
<T>(dep: Dependency<'nan', [T]>): ImpType<'nan', [Complex<T>]> =>
z => complex_binary(dep.nan(z.re), dep.nan(z.im))
export const re =
<T>(dep: Dependency<'re', [T]>): ImpType<'re', [Complex<T>]> =>
z => dep.re(z.re)