I'm looking to have the equivalent of C static_assert(), but only usable against compile-time data, such as type information (which isn't emitted).
type TStrLit_0 = 'a' | 'b' | 'C' | 'd';
type TStrLit_1 = 'a' | 'b' | 'C' | 'd';
type TStrLit_2 = 'a' | 'b' | 'c' | 'd';
type TStrLit_3 = 'a' | 'b' | 'C' ;
type TStrLit_4 = 'a' | 'b' | 'C' |'d' | 'e';
static_assert( TypesAreEqual<TStrLit_0, TStrLit_1>() );
static_assert( !TypesAreEqual<TStrLit_0, TStrLit_2>() );
static_assert( !TypesAreEqual<TStrLit_0, TStrLit_3>() );
static_assert( !TypesAreEqual<TStrLit_0, TStrLit_4>() );
type TObject_0 = { a: number, b: string };
type TObject_1 = { a: number, b: string };
type TObject_2 = { a: number, b: number };
type TObject_3 = { a: number, B: string };
type TObject_4 = { a: number };
type TObject_5 = { a: number, b: string, c: number };
type TObject_6 = { a: any, b: any };
static_assert( TypesAreEqual<TObject_0, TObject_1>() );
static_assert(!TypesAreEqual<TObject_0, TObject_2>() );
static_assert(!TypesAreEqual<TObject_0, TObject_3>() );
static_assert(!TypesAreEqual<TObject_0, TObject_4>() );
static_assert(!TypesAreEqual<TObject_0, TObject_5>() );
static_assert(!TypesAreEqual<TObject_0, TObject_6>() );
What I'm looking for is the generic ability to have typescript-specific, compile-time-only assertions based on the type information.
The compiler already generates the type information, but it's not emitted and thus any runtime assertions have to first change the source to emit extra metadata.
(e.g., for string literals, generating the type from an as const string array, adding typeguard functions, out-of-band tracking the relationship between those string literal types and the source string arrays, ... ugh!)
Having compile-time type information assertions would allow embedding assumed invariants into the code, saving future maintainers pain when they unknowingly violate those invariants.
Does anything like this already exist?
Would this require changes to the TypeScript core, or can it be done with existing functionality?
Thanks!
Visitors to this questions (like me) are potentially more interested in how to achieve an implementation of static_assert that generates no runtime code in the compiled output. OP's answer to their own question is focusing more on a TypesAreEqual implementation, though. In their tsplay.dev link the solution to the former does exist, however! The trick is to use TypeScript generic constraints.
Below is the version I use in my project:
// definition
type static_assert<T extends true> = never;
// usage - does not hold true if reversed
type _check = static_assert<[] extends {} ? true : false>;
Starting with the links in early comments(*), I came up with the following:
type TypesAreEqual2<T, U> = [T] extends [U] ? [U] extends [T] ? true : false : false;
This appears to work for all the (admittedly simple) test cases I could come up with in 20 minutes:
See https://tsplay.dev/wRGDnN
(*) majusebetter pointed to a similar question that jcalz answered in 2018. Alex Wayne provided a tsplayground link. Neither of those solutions was exactly what I was looking for, but both were helpful in getting me the results I was looking for. Thanks to you both!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With