import { Next, IsUnknown, Prev, OptionalKeys } from './utils'; export { Get, At, Checked, Lossy, Optional, A, B, C, D, E, Applied, Valid }; /** Fake `Type` for user friendly error messages */ interface Type extends BaseType { arg: Constraints; constraints: Constraints; names: In extends number ? any : In; } type Constraints = In extends number ? { [K in Prev]: unknown; } : any; /** Fake `Type` for user friendly error messages */ interface OptionalType extends BaseType { constraints: Partial>; names: In extends number ? any : In; } /** fast Type definition */ interface BaseType { constraints: { [k: number]: unknown; }; arguments: { [k: number]: unknown; }; names: Names; } type Names = { [k: string]: number; }; type Normalise = Index extends number ? Next : { [K in Index]: number; }; /** tell whether a Type is applied with all its arguments or not */ type Applied = unknown[] extends This['arguments'] ? false : true; /** tell whether a Type is applied with all the correct arguments */ type Valid = Applied extends false ? false : This['arguments'] extends This['constraints'] ? true : false; /** safely index `this` */ type Get = K extends OptionalKeys ? Exclude : This['arg'][K]; /** - safely index `this` * - optionally take a fallback */ type At>, Fallback = unknown, I extends number = Index extends number ? Index : This['names'][Index]> = IsUnknown extends true ? Fallback : This['arguments'][I]; /** - safely index `this` * - defuse the corresponding type constraint with an inline conditional * - optionally take a fallback */ type Checked>, Fallback = Index extends number ? This['constraints'][Index] : This['constraints'][This['names'][Index]], I extends number = Index extends number ? Index : This['names'][Index]> = This['arguments'][I] extends This['constraints'][I] ? This['arguments'][I] : Fallback; /** - safely index `this` * - works on optional parameters * - defuse the corresponding type constraint with an inline conditional * - optionally take a fallback */ type Optional>, Fallback = Index extends number ? Exclude : Exclude, I extends number = Index extends number ? Index : This['names'][Index]> = This['arguments'][I] extends Exclude ? This['arguments'][I] : Fallback; /** - safely index `this` * - intersect the corresponding type constraint */ type Lossy>, I extends number = Index extends number ? Index : This['names'][Index]> = This['arguments'][I] & This['constraints'][I]; interface NumericValue extends BaseType { constraints: any; arg: { 0: 0; 1: 1; 2: 2; 3: 3; 4: 4; }; } /** - safely index `this` * - intersect the corresponding type constraint * - equals `0` When no argument is supplied */ type A = NumericValue> = Get<0, This>; /** - safely index `this` * - intersect the corresponding type constraint * - equals `1` When no argument is supplied */ type B = NumericValue> = Get<1, This>; /** - safely index `this` * - intersect the corresponding type constraint * - equals `2` When no argument is supplied */ type C = NumericValue> = Get<2, This>; /** - safely index `this` * - intersect the corresponding type constraint * - equals `3` When no argument is supplied */ type D = NumericValue> = Get<3, This>; /** - safely index `this` * - intersect the corresponding type constraint * - equals `4` When no argument is supplied */ type E = NumericValue> = Get<4, This>;