type-plus
Version:
Provides additional types for TypeScript.
120 lines (105 loc) • 4.65 kB
text/typescript
import { tersify } from 'tersify'
import { isConstructor, type AnyConstructor } from '../class/index.js'
import { type AnyFunction } from '../function/any_function.js'
/**
* 💥 *immediate*
* 🚦 *assertion*
*
* Assert the subject satisfies the specified type T
* @type T the type to check against.
*/
export function assertType<T>(subject: T): asserts subject is T
export function assertType<T>(subject: unknown, validator: (s: T) => boolean): asserts subject is T
/**
* @deprecated this is not a failsafe test
*/
export function assertType<T extends new (...args: any) => any>(
subject: unknown,
constructor: T
): asserts subject is InstanceType<T>
export function assertType(subject: unknown, validator?: (s: any) => boolean) {
if (validator) {
if ((isConstructor(validator) && !(subject instanceof validator)) || !validator(subject))
throw new TypeError(`subject fails to satisfy ${tersify(validator)}`)
}
return
}
assertType.isUndefined = function (subject: undefined): asserts subject is undefined {
if (typeof subject !== 'undefined') throw TypeError(`subject is not undefined`)
}
assertType.noUndefined = function <S>(subject: Exclude<S, undefined>): void {
if (typeof subject === 'undefined') throw TypeError(`subject is undefined`)
}
assertType.isNull = function (subject: null): asserts subject is null {
if (subject !== null) throw TypeError(`subject is not null`)
}
assertType.noNull = function <S>(subject: Exclude<S, null>): void {
if (subject === null) throw TypeError(`subject is null`)
}
assertType.isNumber = function (subject: number): asserts subject is number {
if (typeof subject !== 'number') throw TypeError(`subject is not number`)
}
assertType.noNumber = function <S>(subject: Exclude<S, number>): void {
if (typeof subject === 'number') throw TypeError(`subject is number`)
}
assertType.isBoolean = function (subject: boolean): asserts subject is boolean {
if (typeof subject !== 'boolean') throw TypeError(`subject is not boolean`)
}
assertType.noBoolean = function <S>(subject: Exclude<S, boolean>): void {
if (typeof subject === 'boolean') throw TypeError(`subject is boolean`)
}
assertType.isTrue = function (subject: true): asserts subject is true {
if (subject !== true) throw TypeError(`subject is not true`)
}
assertType.noTrue = function <S>(subject: Exclude<S, true>): void {
// @ts-ignore
if (subject === true) throw TypeError(`subject is true`)
}
assertType.isFalse = function (subject: false): asserts subject is false {
if (subject !== false) throw TypeError(`subject is not false`)
}
assertType.noFalse = function <S>(subject: Exclude<S, false>): void {
// @ts-ignore
if (subject === false) throw TypeError(`subject is false`)
}
assertType.isString = function (subject: string): asserts subject is string {
if (typeof subject !== 'string') throw TypeError(`subject is not string`)
}
assertType.noString = function <S>(subject: Exclude<S, string>): void {
if (typeof subject === 'string') throw TypeError(`subject is string`)
}
assertType.isFunction = function (subject: AnyFunction): asserts subject is AnyFunction {
if (typeof subject !== 'function') throw TypeError(`subject is not function`)
}
assertType.noFunction = function <S>(subject: Exclude<S, AnyFunction>): void {
if (typeof subject === 'function') throw TypeError(`subject is function`)
}
/**
* 💀 deprecated. It does not work in all cases.
*
* It passes for function that can be called with `new`.
* If the subject is an arrow function, it can still return true after compilation.
*/
assertType.isConstructor = function (subject: AnyConstructor): asserts subject is AnyConstructor {
if (!isConstructor(subject)) throw TypeError(`subject is not a constructor`)
}
assertType.isError = function (subject: Error): asserts subject is Error {
if (!(subject instanceof Error)) throw TypeError(`subject is not an Error`)
}
assertType.noError = function <S>(subject: Exclude<S, Error>): void {
if (subject instanceof Error) throw TypeError(`subject is an Error`)
}
assertType.isNever = function (_subject: never): asserts _subject is never {}
/**
* creates a custom assertion function with standard TypeError.
* Currently this requires explicity type annotation,
* thus making it hard to use:
* https://github.com/microsoft/TypeScript/issues/41047
*/
assertType.custom = function <T>(validator: (s: T) => boolean): (subject: unknown) => asserts subject is T {
return function (subject) {
if (!validator(subject as any)) throw new TypeError(`subject fails to satisfy ${tersify(validator)}`)
return
}
}
assertType.as = function <T>(_subject: unknown): asserts _subject is T {}