Skip to main content

any

Detection helpers for any, never, unknown, and void.

import type {
  IsAny, IfAny,
  IsNever, IfNever,
  IsUnknown, IfUnknown,
  IsVoid,
  NotAny,
} from '@gentleduck/ttest/any'

Discrimination between any, unknown, never, and void is one of the more error-prone corners of TypeScript. These helpers use stable tricks (intersection collapse, tuple wrapping) to give reliable boolean answers.

IsAny

type IsAny<T> = 0 extends 1 & T ? true : false

true iff T is exactly any. Uses the 0 extends (1 & T) trick: only any collapses that intersection.

type a = IsAny<any>       // true
type b = IsAny<unknown>   // false
type c = IsAny<string>    // false

IfAny

type IfAny<T, Then, Else = T> = IsAny<T> extends true ? Then : Else

Branch on IsAny<T>. Useful for replacing leaked any with a safer fallback.

type Safe<T> = IfAny<T, unknown>  // strips any → unknown

IsNever

type IsNever<T> = [T] extends [never] ? true : false

true iff T is exactly never. The tuple wrap disables distribution, which is required because never distributes to never in a naked conditional.

type a = IsNever<never>  // true
type b = IsNever<undefined>  // false

IfNever

type IfNever<T, Then, Else = T> = IsNever<T> extends true ? Then : Else

Branch on IsNever<T>.

type Result<T> = IfNever<T, 'no result', T>

IsUnknown

type IsUnknown<T> = unknown extends T ? (IsAny<T> extends true ? false : true) : false

true iff T is exactly unknown. The inner IsAny check is required because unknown extends any is also true.

type a = IsUnknown<unknown>  // true
type b = IsUnknown<any>      // false

IfUnknown

type IfUnknown<T, Then, Else = T> = IsUnknown<T> extends true ? Then : Else

Branch on IsUnknown<T>.

IsVoid

type IsVoid<T> = [T] extends [void] ? ([void] extends [T] ? true : false) : false

true iff T is void. Does not consider undefined to be void.

type a = IsVoid<void>       // true
type b = IsVoid<undefined>  // false

NotAny

type NotAny<T> = IsAny<T> extends true ? false : true

Inverse of IsAny. Use as a constraint to refuse any:

function safeFn<T>(t: T & (NotAny<T> extends true ? unknown : never)): T { return t }