67 lines
3.1 KiB
TypeScript
67 lines
3.1 KiB
TypeScript
// Every typocomath type has some associated types; they need
|
|
// to be published as in the following interface. The key is the
|
|
// name of the type, and within the subinterface for that key,
|
|
// the type of the 'type' property is the actual TypeScript type
|
|
// we are associating the other properties to. Note the interface
|
|
// is generic with one parameter, corresponding to the fact that
|
|
// typocomath currently only allows types with a single generic parameter.
|
|
// This way, AssociatedTypes<SubType> can give the associated types
|
|
// for a generic type instantiated with SubType. That's not necessary for
|
|
// the 'undefined' type (or if you look in the `numbers` subdirectory,
|
|
// the 'number' type either) or any concrete type, but that's OK, the
|
|
// generic parameter doesn't hurt in those cases.
|
|
export interface AssociatedTypes<T> {
|
|
undefined: {
|
|
type: undefined
|
|
zero: undefined
|
|
one: undefined
|
|
nan: undefined
|
|
real: undefined
|
|
}
|
|
}
|
|
|
|
type AssociatedTypeNames = keyof AssociatedTypes<unknown>['undefined']
|
|
type ALookup<T, Name extends AssociatedTypeNames> = {
|
|
[K in keyof AssociatedTypes<T>]:
|
|
T extends AssociatedTypes<T>[K]['type'] ? AssociatedTypes<T>[K][Name] : never
|
|
}[keyof AssociatedTypes<T>]
|
|
|
|
export type ZeroType<T> = ALookup<T, 'zero'>
|
|
export type OneType<T> = ALookup<T, 'one'>
|
|
export type WithConstants<T> = T | ZeroType<T> | OneType<T>
|
|
export type NaNType<T> = ALookup<T, 'nan'>
|
|
export type RealType<T> = ALookup<T, 'real'>
|
|
|
|
// The global signature patterns for all operations need to be published in the
|
|
// following interface. Each key is the name of an operation (but note that
|
|
// the Dispatcher will automatically merge operations that have the same
|
|
// name when the first underscore `_` and everything thereafter is stripped).
|
|
// The type of each key should be an interface with two properties: 'params'
|
|
// whose type is the type of the parameter list for the operation, and
|
|
// 'returns' whose type is the return type of the operation on those
|
|
// parameters. These types are generic in a parameter type T which should
|
|
// be interpreted as the type that the operation is supposed to "primarily"
|
|
// operate on, although note that some of the parameters and/or return types
|
|
// may depend on T rather than be exactly T.
|
|
// So note that the example 're' below provides essentially the same
|
|
// information that e.g.
|
|
// `type ReOp<T> = (t: T) => RealType<T>`
|
|
// would, but in a way that is much easier to manipulate in TypeScript,
|
|
// and it records the name of the operation as 're' also by virtue of the
|
|
// key 're' in the interface.
|
|
export interface Operations<T> {
|
|
zero: {params: [WithConstants<T>], returns: ZeroType<T>}
|
|
one: {params: [WithConstants<T>], returns: OneType<T>}
|
|
nan: {params: [T | NaNType<T>], returns: NaNType<T>}
|
|
re: {params: [T], returns: RealType<T>}
|
|
}
|
|
|
|
type OpKey = keyof Operations<unknown>
|
|
|
|
export type OpReturns<Name extends OpKey, T> = Operations<T>[Name]['returns']
|
|
export type OpType<Name extends OpKey, T> =
|
|
(...args: Operations<T>[Name]['params']) => OpReturns<Name, T>
|
|
export type Dependencies<Name extends OpKey, T> = {[K in Name]: OpType<K, T>}
|
|
|
|
|