Skip to content

Ts.Union

Ts / Union

Valid values for discriminant properties in tagged unions.

Import

typescript
import { Ts } from '@wollybeard/kit'

// Access via namespace
Ts.Union.someFunction()
typescript
import * as Ts from '@wollybeard/kit/ts'

// Access via namespace
Ts.Union.someFunction()

Types

[U] DiscriminantPropertyValue

typescript
type DiscriminantPropertyValue = string | number | symbol

Valid values for discriminant properties in tagged unions.

[T] __FORCE_DISTRIBUTION__

typescript
type __FORCE_DISTRIBUTION__ = any

Marker type to make forced union distribution explicit and self-documenting.

TypeScript distributes unions in conditional types when the checked type is a naked type parameter. Using this marker in your conditional type makes the intent explicit to readers.

Examples:

typescript
// Without marker - unclear if distribution is intentional
type 
Transform
<
T
> =
T
extends string ?
Uppercase
<
T
> :
T
// With marker - explicitly documents that distribution is desired type
Transform
<
T
> =
T
extends
__FORCE_DISTRIBUTION__
?
T
extends string ?
Uppercase
<
T
> :
T
: never // More typical usage pattern type
MapUnion
<
T
> =
T
extends
__FORCE_DISTRIBUTION__
?
TransformSingleMember
<
T
>
: never
typescript
// Real-world example: mapping over union members
type 
AddPrefix
<
T
> =
T
extends
__FORCE_DISTRIBUTION__
?
T
extends string ? `prefix_${
T
}` :
T
: never type
Result
=
AddPrefix
<'a' | 'b' | 'c'>
// 'prefix_a' | 'prefix_b' | 'prefix_c'

[T] Include

typescript
type Include<$T, $U> = $T extends $U ? $T : never

Include only types that extend a constraint (opposite of Exclude). Filters a union type to only include members that extend the constraint.

Examples:

typescript
type 
T
= Union.
Include
<string | number | boolean, string | number> // string | number
type
T2
= Union.
Include
<'a' | 'b' | 1 | 2, string> // 'a' | 'b'

[T] ToTuple

typescript
type ToTuple<
  $Union,
  ___L = LastOf<$Union>,
  ___N = [$Union] extends [never] ? true : false,
> = true extends ___N ? []
  : [...ToTuple<Exclude<$Union, ___L>>, ___L]

Convert a union type to a tuple type.

Examples:

typescript
type 
T
= Union.
ToTuple
<'a' | 'b' | 'c'> // ['a', 'b', 'c']

[T] ToIntersection

typescript
type ToIntersection<$U> = ($U extends any ? (k: $U) => void : never) extends
  ((k: infer __i__) => void) ? __i__
  : never

Convert a union type to an intersection type.

Examples:

typescript
type 
U
= {
a
: string } | {
b
: number }
type
I
= Union.
ToIntersection
<
U
> // { a: string } & { b: number }

[T] LastOf

typescript
type LastOf<$T> = ToIntersection<$T extends any ? () => $T : never> extends
  () => infer __r__ ? __r__
  : never

Get the last type in a union.

Examples:

typescript
type 
T
= Union.
LastOf
<'a' | 'b' | 'c'> // 'c'

[T] Expanded

typescript
type Expanded<$Union> = $Union

Force union distribution in conditional types.

Examples:

typescript
type 
T
= Union.
Expanded
<'a' | 'b'> // 'a' | 'b' (forced distribution)

[T] IgnoreAnyOrUnknown

typescript
type IgnoreAnyOrUnknown<$T> = unknown extends $T ? never : $T

Union that ignores any and unknown.

[T] IsAnyMemberExtends

typescript
type IsAnyMemberExtends<$Union, $Type> = (
  // [1] Force distribution
  $Union extends any ? ($Union /* member */ extends $Type ? true : false)
    : never // [1]
) extends false ? false
  : true

Check if any member of a union extends a type.

Examples:

typescript
type 
T1
= Union.
IsAnyMemberExtends
<string | number, string> // true
type
T2
= Union.
IsAnyMemberExtends
<number | boolean, string> // false

[T] IsHas

typescript
type IsHas<$Type, $LookingFor> = _IsHas<$Type, $LookingFor> extends false
  ? false
  : true

Checks if a union type contains a specific type.

Returns true if any member of the union type extends the target type, false otherwise. This is useful for conditional type logic based on union membership.

$Type

  • The union type to search within

$LookingFor

  • The type to search for

Examples:

typescript
type 
HasString
= Union.
IsHas
<string | number | boolean, string> // true
type
HasDate
= Union.
IsHas
<string | number, Date> // false
type
HasLiteral
= Union.
IsHas
<'a' | 'b' | 'c', 'b'> // true
// Useful in conditional types type
ProcessValue
<
T
> = Union.
IsHas
<
T
,
Promise
<any>> extends true ? 'async'
: 'sync' type
R1
=
ProcessValue
<string |
Promise
<string>> // 'async'
type
R2
=
ProcessValue
<string | number> // 'sync'
typescript
// Works with complex types
type 
Events
= {
type
: 'click' } | {
type
: 'hover' } | {
type
: 'focus' }
type
HasClick
= Union.
IsHas
<
Events
, {
type
: 'click' }> // true
// Check for any promise in union type
MaybeAsync
<
T
> = Union.
IsHas
<
T
,
Promise
<any>>
type
R3
=
MaybeAsync
<string |
Promise
<number>> // true
type
R4
=
MaybeAsync
<string | number> // false

[T] Merge

typescript
type Merge<$U> = {
  [
    k in (
      $U extends any ? keyof $U : never
    )
  ]: $U extends any ? (k extends keyof $U ? $U[k] : never) : never
}

Merge all members of a union into a single type.

Examples:

typescript
type 
U
= {
a
: string } | {
b
: number }
type
M
= Union.
Merge
<
U
> // { a: string; b: number }

[T] Is

typescript
type Is<$Type> = [$Type] extends [never] ? false
  : [$Type] extends [ToIntersection<$Type>] ? false
  : true

Check if a type is a union type.

Returns true if the type is a union with multiple members, false if it's a single type or never. This is useful for conditional type logic that needs to handle unions differently from single types.

The check works by: 1. First checking if the type is never (not a union) 2. Then checking if converting the type to an intersection yields the same type

(single types remain unchanged when converted to intersection, unions do not)

Examples:

typescript
// Union types return true
type 
T1
= Union.
Is
<string | number> // true
type
T2
= Union.
Is
<'a' | 'b' | 'c'> // true
type
T3
= Union.
Is
<{
a
: 1 } | {
b
: 2 }> // true
// Single types return false type
T4
= Union.
Is
<string> // false
type
T5
= Union.
Is
<number> // false
type
T6
= Union.
Is
<{
a
: string }> // false
// Special cases type
T7
= Union.
Is
<never> // false
type
T8
= Union.
Is
<any> // false
typescript
// Conditional logic based on union detection
type 
ProcessType
<
T
> = Union.
Is
<
T
> extends true ? 'multiple options'
: 'single option' type
R1
=
ProcessType
<string | number> // 'multiple options'
type
R2
=
ProcessType
<string> // 'single option'