Type-Level Booleans in TypeScript
In TypeScript, we often need to perform conditional logic at compile time. This is particularly useful for creating highly expressive and type-safe utility types. This challenge focuses on building fundamental type-level boolean logic using TypeScript's powerful conditional types. Understanding these concepts is crucial for advanced type manipulation and creating robust type systems.
Problem Description
Your task is to implement a set of type-level boolean operations in TypeScript. You will define three primitive types representing True and False, and then implement logical operations such as And, Or, and Not that operate on these types.
Requirements:
- Primitive Types: Define two distinct types,
TrueandFalse, to represent boolean values at the type level. These should be distinct enough to be differentiated using conditional types. - Logical NOT (
Not<B>): Implement a generic typeNot<B>that takes a boolean typeBand returns its logical negation.Not<True>should resolve toFalse.Not<False>should resolve toTrue.
- Logical AND (
And<A, B>): Implement a generic typeAnd<A, B>that takes two boolean typesAandBand returns their logical conjunction.And<True, True>should resolve toTrue.And<True, False>should resolve toFalse.And<False, True>should resolve toFalse.And<False, False>should resolve toFalse.
- Logical OR (
Or<A, B>): Implement a generic typeOr<A, B>that takes two boolean typesAandBand returns their logical disjunction.Or<True, True>should resolve toTrue.Or<True, False>should resolve toTrue.Or<False, True>should resolve toTrue.Or<False, False>should resolve toFalse.
Expected Behavior:
When these types are used in TypeScript code, the compiler should correctly infer the resulting boolean type based on the input types and the defined logical operations.
Edge Cases:
- Ensure your implementations handle all combinations of
TrueandFalseinputs correctly. - Consider how you will differentiate
TrueandFalseat the type level.
Examples
Example 1: Not Operation
// Assuming True and False are defined and Not<B> is implemented
type NotTrueResult = Not<True>;
// Expected: False
type NotFalseResult = Not<False>;
// Expected: True
Explanation: Not<True> should return False, and Not<False> should return True.
Example 2: And Operation
// Assuming True and False are defined and And<A, B> is implemented
type AndTrueTrue = And<True, True>;
// Expected: True
type AndTrueFalse = And<True, False>;
// Expected: False
type AndFalseTrue = And<False, True>;
// Expected: False
type AndFalseFalse = And<False, False>;
// Expected: False
Explanation: The And operation follows standard boolean logic where the result is True only if both inputs are True.
Example 3: Or Operation
// Assuming True and False are defined and Or<A, B> is implemented
type OrTrueTrue = Or<True, True>;
// Expected: True
type OrTrueFalse = Or<True, False>;
// Expected: True
type OrFalseTrue = Or<False, True>;
// Expected: True
type OrFalseFalse = Or<False, False>;
// Expected: False
Explanation: The Or operation follows standard boolean logic where the result is False only if both inputs are False.
Constraints
- Your solution must use only TypeScript's built-in type system. No runtime JavaScript code is involved.
- The primitive
TrueandFalsetypes should be defined using interfaces or type aliases. - The logical operations (
Not,And,Or) must be implemented as generic conditional types. - The solution should be concise and idiomatic TypeScript.
Notes
- A common approach for defining primitive types like
TrueandFalseis to use literal types (e.g.,trueandfalseas type parameters, or dedicated interface markers). Think about how you can leverage conditional types to differentiate between them. - Consider how the
extendskeyword in conditional types can be used to check the "value" of your type-level booleans. - You can build more complex logic by combining these basic operations. For instance,
XORcan be implemented usingOrandAnd.