Skip to content

Commit

Permalink
Add Type.Assert HKT that implements behavior of TypeScript as ass…
Browse files Browse the repository at this point in the history
…ertions
  • Loading branch information
MajorLift committed Mar 27, 2024
1 parent a3c07f5 commit ebc78e3
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/type/assert.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Test, Type } from '..'

type Assert_Spec = [
/**
* Can cast a type to itself.
*/
Test.Expect<Type._$assert<true, true>, true>,

/**
* Can cast a type to a subtype.
*/
Test.Expect<Type._$assert<boolean, true>, true>,

/**
* Can cast a type to a supertype.
*/
Test.Expect<Type._$assert<true, boolean>, boolean>,

/**
* Returns `never` if the types are not related.
*/
Test.Expect<Type._$assert<boolean, 0>, never>
]
43 changes: 43 additions & 0 deletions src/type/assert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Kind } from '..'

/**
* `_$assert` is a generic type that casts a type `T` to a type `U`, but only if `U` is a narrower or wider version of `T`.
* If an impossible coercion to an unrelated type is attempted, it returns `never`.
*
* This behavior is modeled after TypeScript's type assertion using the `as` operator.
* @see {@link Type._$cast} for a more permissive version of this type that only performs downcasts or coercions to unrelated types.
*
* @template T - The type to assert.
* @template U - The type to assert to.
*
* @example
* type T0 = _$assert<true, true> // true
* type T1 = _$assert<boolean, true> // true
* type T2 = _$assert<true, boolean> // boolean
* type T3 = _$assert<boolean, 0> // never
*/
export type _$assert<T, U> = [T] extends [U] ? U : [U] extends [T] ? U : never

interface Assert_T<T> extends Kind.Kind {
f(x: this[Kind._]): _$assert<typeof x, T>
}

/**
* `Assert` is a type-level function that casts a type `T` to a type `U`, but only if `U` is a more or less specific version of `T`.
* If an impossible coercion to an unrelated type is attempted, it returns `never`.
*
* This behavior is modeled after TypeScript's type assertion using the `as` operator.
* @see {@link Type._$cast} for a more permissive version of this function that only performs downcasts or coercions to unrelated types.
*
* @template T - The type to assert.
* @template U - The type to assert to.
*
* @example
* type T0 = $<$<Assert, true>, true> // true
* type T1 = $<$<Assert, boolean>, true> // true
* type T2 = $<$<Assert, true>, boolean> // boolean
* type T3 = $<$<Assert, boolean>, 0> // never
*/
export interface Assert extends Kind.Kind {
f(x: this[Kind._]): Assert_T<typeof x>
}
1 change: 1 addition & 0 deletions src/type/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './assert'
export * from './cast'
export * from './display'
export * from './infer'
Expand Down

0 comments on commit ebc78e3

Please sign in to comment.