Skip to main content

Utilities

Collection of utility functions for type checking, object manipulation, and common transformations. All exports are tree-shakeable.

Import

import {
  // Type guards
  isFunction, isString, isNumber, isBoolean,
  isObject, isArray, isElement,
  isNull, isUndefined, isNullOrUndefined,
  isPrimitive, isSymbol, isNaN,
  // Object manipulation
  mergeDeep,
  // Utilities
  useId, clamp, range, debounce
} from '#v0/utilities'

Type Guards

Type guard functions that perform runtime type checking with TypeScript type narrowing.

isFunction

Checks if a value is a function.
function isFunction(item: unknown): item is Function
item
unknown
The value to check
returns
boolean
True if the value is a function

Usage

isFunction(() => {})  // true
isFunction('string')  // false

const value: unknown = someValue
if (isFunction(value)) {
  value() // TypeScript knows value is a function
}

isString

Checks if a value is a string.
function isString(item: unknown): item is string
item
unknown
The value to check
returns
boolean
True if the value is a string

Usage

isString('hello')  // true
isString(123)      // false

const value: unknown = someValue
if (isString(value)) {
  console.log(value.toUpperCase()) // TypeScript knows value is a string
}

isNumber

Checks if a value is a number.
function isNumber(item: unknown): item is number
item
unknown
The value to check
returns
boolean
True if the value is a number (including NaN)
This returns true for NaN. Use isNaN() to check for NaN specifically.

Usage

isNumber(123)       // true
isNumber(NaN)       // true
isNumber('123')     // false

isBoolean

Checks if a value is a boolean.
function isBoolean(item: unknown): item is boolean
item
unknown
The value to check
returns
boolean
True if the value is a boolean

Usage

isBoolean(true)   // true
isBoolean(false)  // true
isBoolean(0)      // false
isBoolean(1)      // false

isObject

Checks if a value is a plain object (excludes null and arrays).
function isObject(item: unknown): item is Record<string, unknown>
item
unknown
The value to check
returns
boolean
True if the value is a plain object
Returns false for null and arrays, even though typeof null === 'object' and typeof [] === 'object' in JavaScript.

Usage

isObject({})        // true
isObject({ a: 1 })  // true
isObject(null)      // false
isObject([])        // false

const value: unknown = someValue
if (isObject(value)) {
  console.log(value.someProperty) // TypeScript knows value is an object
}

isArray

Checks if a value is an array.
function isArray(item: unknown): item is unknown[]
item
unknown
The value to check
returns
boolean
True if the value is an array

Usage

isArray([])        // true
isArray([1, 2, 3]) // true
isArray('string')  // false
isArray({})        // false

isElement

Checks if a value is a DOM Element.
function isElement(item: unknown): item is Element
item
unknown
The value to check
returns
boolean
True if the value is a DOM Element

Usage

isElement(document.body) // true
isElement(document.querySelector('div')) // true (if found)
isElement('string')      // false
isElement(null)          // false

isNull

Checks if a value is null.
function isNull(item: unknown): item is null
item
unknown
The value to check
returns
boolean
True if the value is null

Usage

isNull(null)      // true
isNull(undefined) // false
isNull(0)         // false
isNull('')        // false

isUndefined

Checks if a value is undefined.
function isUndefined(item: unknown): item is undefined
item
unknown
The value to check
returns
boolean
True if the value is undefined

Usage

isUndefined(undefined) // true
isUndefined(null)      // false
isUndefined(0)         // false

isNullOrUndefined

Checks if a value is null or undefined.
function isNullOrUndefined(item: unknown): item is null | undefined
item
unknown
The value to check
returns
boolean
True if the value is null or undefined
Uses loose equality (== null) which matches both null and undefined.

Usage

isNullOrUndefined(null)      // true
isNullOrUndefined(undefined) // true
isNullOrUndefined(0)         // false
isNullOrUndefined('')        // false

// Useful for optional values
function process(value?: string) {
  if (!isNullOrUndefined(value)) {
    console.log(value.toUpperCase())
  }
}

isPrimitive

Checks if a value is a primitive (string, number, or boolean).
function isPrimitive(item: unknown): item is string | number | boolean
item
unknown
The value to check
returns
boolean
True if the value is a string, number, or boolean

Usage

isPrimitive('hello') // true
isPrimitive(123)     // true
isPrimitive(true)    // true
isPrimitive({})      // false
isPrimitive(null)    // false
isPrimitive(undefined) // false

isSymbol

Checks if a value is a symbol.
function isSymbol(item: unknown): item is symbol
item
unknown
The value to check
returns
boolean
True if the value is a symbol

Usage

isSymbol(Symbol('test')) // true
isSymbol('symbol')       // false

isNaN

Checks if a value is NaN (Not a Number).
function isNaN(item: unknown): item is number
item
unknown
The value to check
returns
boolean
True if the value is NaN
Uses Number.isNaN() which only returns true for the actual NaN value, unlike the global isNaN() which coerces the argument to a number first.

Usage

isNaN(NaN)         // true
isNaN(123)         // false
isNaN('hello')     // false (unlike global isNaN)
isNaN(undefined)   // false (unlike global isNaN)

Object Manipulation

mergeDeep

Deeply merges source objects into a target object.
function mergeDeep<T extends object>(
  target: T,
  ...sources: DeepPartial<T>[]
): T
target
T extends object
The target object to merge into (will be mutated)
sources
DeepPartial<T>[]
One or more source objects to merge from
returns
T
The mutated target object
  • Mutates the target object in place
  • Arrays are replaced, not merged
  • Protected against prototype pollution (__proto__, constructor, prototype)

Usage

// Basic merge
const target = { a: 1, b: { c: 2 } }
mergeDeep(target, { b: { d: 3 } })
// target is now { a: 1, b: { c: 2, d: 3 } }

// Multiple sources
const result = mergeDeep({}, { a: 1 }, { b: 2 }, { c: 3 })
// result is { a: 1, b: 2, c: 3 }

// Arrays are replaced
mergeDeep({ arr: [1, 2] }, { arr: [3] })
// { arr: [3] }

// Deep nested objects
const config = {
  theme: {
    colors: { primary: 'blue' },
    spacing: { base: 16 }
  }
}

mergeDeep(config, {
  theme: {
    colors: { secondary: 'red' }
  }
})
// {
//   theme: {
//     colors: { primary: 'blue', secondary: 'red' },
//     spacing: { base: 16 }
//   }
// }

Utilities

useId

Generates a unique ID, using Vue’s useId when in component context.
function useId(): string
returns
string
A unique string ID
  • In component setup/lifecycle: Uses Vue’s useId() for SSR-safe hydration
  • Outside components: Falls back to sequential counter (v0-0, v0-1, …)
  • Vapor mode compatible

Usage

// In component setup - SSR safe
const id = useId() // 'v:0', 'v:1', etc. (Vue's format)

// Outside component - counter fallback
const id = useId() // 'v0-0', 'v0-1', etc.
<script setup lang="ts">
import { useId } from '#v0/utilities'

const inputId = useId()
const labelId = useId()
</script>

<template>
  <div>
    <label :for="inputId" :id="labelId">
      Username
    </label>
    <input :id="inputId" :aria-labelledby="labelId" />
  </div>
</template>

clamp

Clamps a value between a minimum and maximum.
function clamp(value: number, min = 0, max = 1): number
value
number
required
The value to clamp
min
number
default:"0"
The minimum value
max
number
default:"1"
The maximum value
returns
number
The clamped value

Usage

clamp(5, 0, 10)   // 5
clamp(-5, 0, 10)  // 0
clamp(15, 0, 10)  // 10
clamp(0.5)        // 0.5 (default range 0-1)
clamp(1.5)        // 1 (default max is 1)

// Useful for percentages
const percentage = clamp(progress / total, 0, 1)

// Useful for ranges
const volume = clamp(newVolume, 0, 100)

range

Creates an array of sequential numbers.
function range(length: number, start = 0): number[]
length
number
required
The length of the array to create
start
number
default:"0"
The starting index
returns
number[]
An array of sequential numbers

Usage

range(3)      // [0, 1, 2]
range(3, 1)   // [1, 2, 3]
range(5, 10)  // [10, 11, 12, 13, 14]
range(0)      // []

// Useful for rendering
const items = range(10).map(i => ({ id: i, name: `Item ${i}` }))

// Useful for pagination
const pages = range(totalPages, 1) // [1, 2, 3, ...]

debounce

Debounces a function call by the specified delay.
function debounce<T extends (...args: any[]) => any>(
  fn: T,
  delay: number
): {
  (...args: Parameters<T>): void
  clear(): void
  immediate(...args: Parameters<T>): void
}
fn
T
required
The function to debounce
delay
number
required
The delay in milliseconds
returns
DebouncedFunction
A debounced function with clear() and immediate() methods

Usage

const debouncedFn = debounce(() => console.log('called'), 500)

// Will call after 500ms of inactivity
debouncedFn()

// Cancel pending call
debouncedFn.clear()

// Call immediately
debouncedFn.immediate()
<script setup lang="ts">
import { debounce } from '#v0/utilities'

const search = ref('')

const performSearch = debounce((query: string) => {
  console.log('Searching for:', query)
  // Perform API call
}, 300)

watch(search, (value) => {
  performSearch(value)
})

onUnmounted(() => {
  performSearch.clear()
})
</script>

<template>
  <input v-model="search" placeholder="Search..." />
</template>

Build docs developers (and LLMs) love