/***** * Every typocomath type has some associated types; they need * to be published 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 generic types with a single * generic parameter. This way, AssociatedTypes 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) or any concrete type, * but that's OK, the generic parameter doesn't hurt in those cases. ****/ export interface AssociatedTypes { undefined: { type: undefined zero: undefined one: undefined nan: undefined real: undefined } } type AssociatedTypeNames = keyof AssociatedTypes['undefined'] type ALookup = { [K in keyof AssociatedTypes]: T extends AssociatedTypes[K]['type'] ? AssociatedTypes[K][Name] : never }[keyof AssociatedTypes] // For everything to compile, zero and one must be subtypes of T: export type ZeroType = ALookup & T export type OneType = ALookup & T // But I believe 'nan' really might not be, like I think we will have to use // 'undefined' for the nan of 'bigint', as it has nothing at all like NaN, // so don't force it: export type NaNType = ALookup export type RealType = ALookup /***** * 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) => RealType` * 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 Signatures { zero: (a: T) => ZeroType one: (a: T) => OneType // nan needs to be able to operate on its own output for everything // else to compile. That's why its parameter type is widened: nan: (a: T | NaNType) => NaNType re: (a: T) => RealType } type SignatureKey = keyof Signatures export type Signature, T> = Signatures[Name] export type Returns, T> = ReturnType[Name]> export type Dependencies, T> = {[K in Name]: Signature} export type AliasOf = T & {aliasOf?: Name}