import type { Array, Constants, Pretty } from '.'; /** * The `IsNever` type checks if a given type {@link TValue} strictly equals to `never`. * * @template TValue - The type variable to be checked against `never`. * * @example * type A = IsNever; // This will resolve to 'false' because number is not `never` * type B = IsNever>; // This will resolve to 'true' because Cast<'foo', number> strictly equals to never. * * @see {@link StrictEqual} - The Type used internally to make the comparison. * @remark * Please make sure to understand the difference between `never` and other types in TypeScript before using `IsNever` for any conditional checks */ export type IsNever = StrictEqual; /** * The `IsNotNever` type checks if a given type {@link TValue} does not strictly equals to `never`. * * It is useful in conditional types to verify if the variable of type {@link TValue} is something other than `never`. * It complements the {@link IsNever} type by negating the result using the {@link Not} utility type. * * @template TValue - The type variable to be checked for inequality against `never`. * * @example * type IsNotNeverNumber = IsNotNever; // Evaluates to 'true' because number is not 'never'. * type IsNotNeverNever = IsNotNever; // Evaluates to 'false' because `never` equals to 'never'. * * @see {@link IsNever} - The type used internally to check if {@link TValue} is `never`. */ export type IsNotNever = Not>; /** * The `IsTrue` type evaluates if the given {@link TValue} strictly equals {@link Constants.True}. * * @template TValue - The type to evaluate. * * @example * type A = IsTrue; // This will resolve to Constants.True * type B = IsTrue; // This will resolve to Constants.False */ export type IsTrue = [TValue] extends [Constants.True] ? Constants.True : Constants.False; /** * The `IsNotTrue` type evaluates if the given {@link TValue} is not strictly equal to {@link Constants.True}. * * It basically negates the output of {@link IsTrue}. * * @template TValue - The type to evaluate. * * @example * type A = IsNotTrue; // This will resolve to Constants.False * type B = IsNotTrue; // This will resolve to Constants.True * */ export type IsNotTrue = Not>; /** * The `IsFalse` type evaluates if the given {@link TValue} strictly equals {@link Constants.False}. * * @template TValue - The type to evaluate. * * @example * type A = IsFalse; // This will resolve to Constants.False * type B = IsFalse; // This will resolve to Constants.True */ export type IsFalse = [TValue] extends [Constants.False] ? Constants.True : Constants.False; /** * The `IsNotFalse` type evaluates if the value provided does not strictly equal {@link Constants.False}. * * It basically negates the output of {@link IsFalse}. * * @template TValue - The type to be evaluated. * * @example * type A = IsNotFalse; // This will resolve to Constants.False * type B = IsNotFalse; // This will resolve to Constants.True */ export type IsNotFalse = Not>; /** * The `StrictEqual` type evaluates if two types, {@link TValue} and {@link TMatch}, are strictly the same. * * In other words, it checks if {@link TValue} extends {@link TMatch} and if {@link TMatch} extends {@link TValue} at the same time, * hence ensuring complete type match. * * @template TValue - The first type to be compared. * @template TMatch - The second type to be compared. * * @returns Either {@link Constants.True} or {@link Constants.False}. * * @example * // With a regular extends * type A = "string" extends string ? true : false; // Result: true * * // With `StrictEqual` * type B = StrictEqual<"string", string>; // Result: false */ export type StrictEqual = And, Extends>; /** * The `NotStrictEqual` type is a utility type that checks if two types, {@link TValue} and {@link TMatch}, are different using strict equality comparison. * * * @template TValue - The first type to be compared. * @template TMatch - The second type to be compared against the first one. * * @returns Either {@link Constants.True} or {@link Constants.False} * * @see {@link StrictEqual} * * @example * // Comparing basic types * type BasicTypeCheck = NotStrictEqual; // Result: Constants.True (because `number` and `string` types are not the same) * * // Comparing complex types * type MyType = { a: number, b: string }; * type OtherType = { a: number, c: boolean }; * type ComplexTypeCheck = NotStrictEqual; // Result: Constants.True (because `MyType` and `OtherType` do not have the same structure) * */ export type NotStrictEqual = Not>; /** * The `Extends` type evaluates if a type, identified by {@link TLeft}, extends another one, identified by {@link TRight}. * * @template TLeft - The type to be tested if it extends {@link TRight}. * @template TRight - The base type used for comparison. * * @note To understand more about conditional types and the `extends` keyword in TypeScript see {@link https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types} * * @remark * The check `[TLeft] extends [TRight]` is wrapped in a tuple because TypeScript's `extends` behaves differently with unions in the context of distributivity. * * Wrapping in a tuple deactivates this distributive behavior and makes the check behave as expected in all cases. * * @example * The type `"hello"` is a subtype of `string` so it extends `string` * ```typescript * type isString = Extends<"hello", string>; * // output: Constants.True *``` * * The type `string` does not extend `"hello"`. * ```typescript * type notSpecificString = Extends; * // output: Constants.False * ``` */ export type Extends = [TLeft] extends [TRight] ? Constants.True : Constants.False; /** * The `DoesNotExtends` type checks if {@link TLeft} does not extend {@link TRight}. * * @template TLeft - The type to be tested if it does not extend {@link TRight}. * @template TRight - The base type used for comparing if it is not extended by {@link TLeft}. * * @see {@link Extends} */ export type DoesNotExtends = Not>; /** * The `Not` type defines a type-level boolean negation operation. * * More concretely, if {@link TExpression} strictly equates to {@link Constants.True} then the result of `Not` would be {@link Constants.False}, and vice versa. * * @template TExpression - The type level boolean expression to be negated. It should extend {@link Constants.BooleanValue}. * * @see {@link Constants.BooleanValue} * * @example * ```typescript * // Using expression that equates to `true` * type A = Not; // Results in Constants.False * * // Using `true` wrapped inside another type * type B = Not>; // Results in Constants.False * * // Using expression that equates to `false` * type C = Not; // Results in Constants.True * * // Using `false` wrapped inside another type * type D = Not>; // Results in Constants.True * ``` */ export type Not = If; /** * The `If` type is a conditional type that accepts a type level boolean expression (`true` or `false` represented as {@link Constants.BooleanValue}), * and two result types, one if the expression is {@link Constants.True} and the other if it's {@link Constants.False}. * * It's an implementation of the traditional 'if/then/else' logic, but at the type level. * * @template TExpression - The type level boolean expression to evaluate. It should extend {@link Constants.BooleanValue}. * @template TOnTrue - The type returned if {@link TExpression} resolves to {@link Constants.True}. * @template TOnFalse - The type returned if {@link TExpression} resolves to {@link Constants.False}. It defaults to `never`. * * @example * Here's an example using `If` with {@link TExpression} that's resolved to {@link Constants.False}. * * As a result, the type applied will be 'FalseCase'. * ```typescript * type FalseCase = 'This is False'; * type TrueCase = 'This is True'; * * type Result = If; // Result: 'This is False' * ``` * * Conversely, if we replace {@link TExpression} with {@link Constants.True}, the applicable type will be 'TrueCase'. * ```typescript * type ExampleTrue = If; // Result: 'This is True case' * ``` * * If the third type argument is omitted, and the expression is false, the `If` type will resolve to `never`. * ```typescript * type ExampleNever = If; // Result: never * ``` */ export type If = [ TExpression ] extends [Constants.True] ? TOnTrue : TOnFalse; /** * The `MatchFirst` type is a type-level logic that matches the first truthy `Test` in a given array of {@link Test} types * and resolves to corresponding type value ('TValue') of that {@link Test}. * * If no truthy {@link Test} is found, it resolves to a default type {@link TDefault}. * * @note This type is particularly useful for checking multiple conditions and matching the type to * whichever condition proves true first, similar to a switch-case or a series of if-else statements in traditional programming. * * @template TTests - An array of {@link Test} types that the type checker will iterate over to find the first truthy test. * @template TDefault - The default value that will be used if none of the {@link Test} types in {@link TTests} prove true. Defaults to `never`. * * @see {@link Test} * @see {@link MatchAllIntersect} * * @example * Here's an example showing how `MatchFirst` can be used with series of {@link Test} types. * * We have declared a Test array containing two Test types. * - The first Test type checks if 'T' is a string. * * If true, it will return 'string type', else it moves to the next Test type. * - The next Test type checks if 'T' is a number. * * If true, it will return 'number type'. * - The third argument is the default type which would be returned if all the conditions fail. In our case its 'unknown type'. * * ```typescript * type T = string; // you can replace 'T' with 'number' or 'boolean' to test. * * type IsString = Test, 'string type'>; * type IsNumber = Test, 'number type'>; * type Tests = [IsString, IsNumber]; * * type Result = MatchFirst; // Result would be 'string type' as 'T' is string. * ``` * */ export type MatchFirst = TTests extends [ infer THead extends Test, ...infer TTail extends Test[] ] ? THead extends Test ? If, MatchFirst, TDefault>> : never : never; /** * The `MatchAllIntersect` type enables the creation of an intersection type from a sequence of conditional types. * * It is useful in scenarios where the properties of an object are to be picked conditionally, based on evaluated boolean expressions. * * @template TTests - A tuple type where each member extends {@link Test}. * * It's this sequence of tests that determine the properties to be picked. * * @template TDefault - This type is used whenever a member of `TTests` doesn't match the expected type or when the * tuple is empty, meaning that no conditions were provided. * * This defaults to `unknown`. * * @see {@link Test} * @see {@link MatchFirst} * * @example * ```typescript * type Test1 = Test; * type Test2 = Test; * type Test3 = Test; * * type Result = MatchAllIntersect<[Test1, Test2, Test3]>; * // The Result will be { sort?: string } & { populate?: string[] } * ``` * * In the example above, only Test1 and Test3 resolves to true case and thus the result excludes the type `{ fields?: number[] }`. * * There is also a default case `{}` that would be returned if *all* the tests in `TTests` were false. * * This can be customized by using the second type parameter {@link TDefault}. * ```typescript * type Test3 = Test; * type Test4 = Test; * * type ResultDefault = MatchAllIntersect<[Test3, Test4], {}>; // The Result will be {} * ``` */ export type MatchAllIntersect = TTests extends [ infer THead extends Test, ...infer TTail extends Test[] ] ? THead extends Test ? // Actual test case evaluation If & If, MatchAllIntersect, TDefault> : TDefault : TDefault; /** * The `Test` type pairs a boolean expression and a corresponding value. * * The elements of the type pair are: * 1. A boolean value ({@link TExpression}), which acts as the conditional expression. * 2. A corresponding value ({@link TValue}), which is usually returned/read when the conditional expression is `true`. * * @template TExpression - A boolean value that will be used as the conditional expression. It extends from {@link Constants.BooleanValue}. * @template TValue - The corresponding value that will be returned when the `TExpression` is `true`. * * @see {@link Constants.BooleanValue} * @see {@link MatchFirst} * @see {@link MatchAllIntersect} * * @example * Suppose we're writing a type level function that behaves differently based on whether the generic type parameter extends a string or a number. * * We can represent these two conditions using the `Test` type, like this: * * ```typescript * type T = number; // replace this with different types to see the outcome * * // Defining two Test conditions * type IsString = Test, 'Input is a string'>; * type IsNumber = Test, 'Input is a number'>; * * type DetectedType = MatchFirst<[IsString, IsNumber], 'unknown type'>; // The Result will be 'Input is a number' * ``` */ export type Test = [TExpression, TValue]; /** * The `Some` type is used for performing a boolean OR operation at the type level over all elements of {@link TExpressions}. * * The OR operation is applied between every two adjacent types in the array from left to right until a resulting type is derived. * * It's conceptually similar to the `Array.prototype.some()` method, but at the type level rather than the value level. * * If the array is empty, it returns {@link Constants.False}. * * @template TExpressions - An array of types extending {@link Constants.BooleanValue}. Use this to specify the types to apply the OR operation on. * * @see {@link Every} * @see {@link Constants.BooleanValue} * * * @example * ```typescript * type Example1 = Some<[Constants.False, Constants.False, Constants.False]>; // Result: Constants.False * type Example2 = Some<[Constants.False, Constants.True, Constants.False]>; // Result: Constants.True * type Example3 = Some<[Constants.True, Constants.True, Constants.True]>; // Result: Constants.True * type Example4 = Some<[Constants.False]>; // Result: Constants.False * type Example5 = Some<[Constants.True]>; // Result: Constants.True * type Example6 = Some<[]>; // Result: Constants.False * ``` */ export type Some = TExpressions extends [ infer THead extends Constants.BooleanValue, ...infer TTail extends Constants.BooleanValue[] ] ? If, Or>, Or> : never; /** * The `Every` type is used to perform a logical AND operation on a sequence of type-level boolean values represented as {@link Constants.BooleanValue}. * * The AND operation is applied between every two adjacent types in the array from left to right until a resulting type is derived. * * It's conceptually similar to the `Array.prototype.every()` method, but at the type level rather than the value level. * * If the array is empty, it returns {@link Constants.True}. * * @template TExpressions - An array of types extending {@link Constants.BooleanValue}. Use this to specify the types to apply the AND operation on. * * @example * ```typescript * type Example1 = Every<[Constants.False, Constants.False, Constants.False]>; // Result: Constants.False * type Example2 = Every<[Constants.False, Constants.True, Constants.False]>; // Result: Constants.False * type Example3 = Every<[Constants.True, Constants.True, Constants.True]>; // Result: Constants.True * type Example4 = Every<[Constants.False]>; // Result: Constants.False * type Example5 = Every<[Constants.True]>; // Result: Constants.True * type Example6 = Every<[]>; // Result: Constants.True * ``` * * @see {@link Some} * @see {@link Constants.BooleanValue} */ export type Every = TExpressions extends [ infer THead extends Constants.BooleanValue, ...infer TTail extends Constants.BooleanValue[] ] ? If, And>, And> : never; /** * The `And` type is a type-level logical conjugation (AND) operator. * * It calculates boolean AND operation of {@link IsTrue} derived from the input types {@link TLeft} and {@link TRight}. * * @template TLeft - The left hand operand of the AND operation. It should extend {@link Constants.BooleanValue}. * @template TRight - The right hand operand of the AND operation. It should extend {@link Constants.BooleanValue}. * * @see {@link IsTrue} * * @example * ```typescript * // Constants.True AND Constants.True * type Example1 = And; // Result: Constants.True * * // Constants.False AND Constants.True * type Example2 = And; // Result: Constants.False * * // Constants.False AND Constants.False * type Example3 = And; // Result: Constants.False * ``` */ export type And = IsTrue | IsTrue>; /** * The `Or` type is a type-level logical conjugation (OR) operator. * * It calculates boolean OR operation of {@link IsTrue} derived from the input types {@link TLeft} and {@link TRight}. * * @template TLeft - The left hand operand of the OR operation. It should extend {@link Constants.BooleanValue}. * @template TRight - The right hand operand of the OR operation. It should extend {@link Constants.BooleanValue}. * * @see {@link IsTrue} * * @example * ```typescript * // Constants.True OR Constants.True * type Example1 = Or; // Result: Constants.True * * // Constants.False OR Constants.True * type Example2 = Or; // Result: Constants.True * * // Constants.False OR Constants.False * type Example3 = Or; // Result: Constants.False * ``` */ export type Or = Not | IsTrue>>; /** * The `Intersect` type constructs a new type by intersecting a list of types. * * @template TValues - The tuple of types to be intersected extending from `unknown[]`. * * @remark This type can easily be replaced by a regular intersection in most scenario. * * The main use-case would be when dealing with a list of types of unknown length. * * In the codebase, it's used mainly for aesthetics reasons (formatting of type params vs intersection members). * * @example * ```typescript * // Defining Attribute Options * interface ConfigurableOption { * configurable?: boolean; * } * * interface RequiredOption { * required?: boolean; * } * * // Intersecting Attribute Options * type AttributeOptions = Intersect< * [ ConfigurableOption, RequiredOption ] * > * * // Now `AttributeOptions` contains properties from both `ConfigurableOption` and `RequiredOption`. * ``` * * @example * ```typescript * // Using `Intersect` to define a complete Attribute type * interface BasicAttribute { * name: string; * type: string; * } * * interface AttributeProperties { * minLength?: number; * maxLength?: number; * } * * type Attribute = Intersect<[ * BasicAttribute, * AttributeProperties, * AttributeOptions * ]> * * // Now, `Attribute` type contains * // - name and type fields from `BasicAttribute` * // - minLength and maxLength fields from AttributeProperties * // - configurable and required fields from `AttributeOptions` * ``` */ export type Intersect = TValues extends [ infer THead, ...infer TTail extends unknown[] ] ? Pretty, Intersect, unknown>> : never; //# sourceMappingURL=expression.d.ts.map