Skip to main content
Back to Tools
Packages

ts-utils — TypeScript Utility Functions

A lightweight collection of TypeScript utility functions for common operations. Zero dependencies, tree-shakeable, fully typed. Includes array helpers, string manipulation, object utilities, and type guards.

typescript utilities npm open-source library

Published March 21, 2026

Installation

npm install @shopubu/ts-utils
# or
pnpm add @shopubu/ts-utils
# or
yarn add @shopubu/ts-utils

Quick Start

import { groupBy, pick, slugify, isNonNullable } from '@shopubu/ts-utils'

// Group array items by key
const grouped = groupBy(users, 'role')
// { admin: [...], user: [...] }

// Pick specific keys from object
const subset = pick(user, ['name', 'email'])
// { name: '...', email: '...' }

// Generate URL-safe slugs
const slug = slugify('Hello World!')
// 'hello-world'

// Type-safe null filtering
const values = [1, null, 2, undefined, 3].filter(isNonNullable)
// Type: number[] (not (number | null | undefined)[])

API Reference

Array Utilities

groupBy<T>(array: T[], key: keyof T): Record<string, T[]>

Groups array elements by a key property. Returns a new object without mutating the input.

const products = [
  { name: 'Shirt', category: 'clothing' },
  { name: 'Pants', category: 'clothing' },
  { name: 'Phone', category: 'electronics' },
]

const grouped = groupBy(products, 'category')
// { clothing: [Shirt, Pants], electronics: [Phone] }

chunk<T>(array: T[], size: number): T[][]

Splits an array into chunks of the specified size. The last chunk may be smaller.

chunk([1, 2, 3, 4, 5], 2)
// [[1, 2], [3, 4], [5]]

unique<T>(array: T[], key?: keyof T): T[]

Returns unique elements. When a key is provided, uniqueness is determined by that property.

unique([1, 2, 2, 3, 3, 3])
// [1, 2, 3]

unique(users, 'email')
// Unique users by email

compact<T>(array: (T | null | undefined | false | 0 | '')[]): T[]

Removes all falsy values from an array with proper type narrowing.

compact([0, 1, false, 2, '', 3, null, undefined])
// [1, 2, 3] — Type: number[]

Object Utilities

pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>

Creates a new object with only the specified keys. Never mutates the original.

const user = { name: 'Fatih', email: '[email protected]', password: 'secret' }
const safe = pick(user, ['name', 'email'])
// { name: 'Fatih', email: '[email protected]' }

omit<T, K extends keyof T>(obj: T, keys: K[]): Omit<T, K>

Creates a new object without the specified keys.

const user = { name: 'Fatih', email: '[email protected]', password: 'secret' }
const safe = omit(user, ['password'])
// { name: 'Fatih', email: '[email protected]' }

deepMerge<T>(target: T, source: Partial<T>): T

Deep merges two objects. Returns a new object — both inputs remain unchanged.

const defaults = { theme: { color: 'blue', size: 'md' }, debug: false }
const overrides = { theme: { color: 'red' } }
const config = deepMerge(defaults, overrides)
// { theme: { color: 'red', size: 'md' }, debug: false }

String Utilities

slugify(str: string): string

Converts a string to a URL-safe slug. Handles unicode, diacritics, and special characters.

slugify('Hello World!')       // 'hello-world'
slugify('Türkçe Karakterler') // 'turkce-karakterler'
slugify('  Multiple   Spaces  ') // 'multiple-spaces'

truncate(str: string, length: number, suffix?: string): string

Truncates a string at the specified length, breaking at word boundaries. Default suffix is ....

truncate('This is a long sentence that needs trimming', 20)
// 'This is a long...'

truncate('Custom suffix example', 15, ' [more]')
// 'Custom suffix [more]'

Type Guards

isNonNullable<T>(value: T): value is NonNullable<T>

Type-safe null/undefined check that narrows the type correctly. Essential for .filter() chains.

const items: (string | null | undefined)[] = ['a', null, 'b', undefined]
const filtered = items.filter(isNonNullable)
// Type: string[] (correctly narrowed)

isString(value: unknown): value is string

Runtime string type check with type narrowing.

const value: unknown = getInput()
if (isString(value)) {
  // value is now typed as string
  value.toUpperCase()
}

isNumber(value: unknown): value is number

Runtime number type check. Excludes NaN.

isNumber(42)        // true
isNumber('42')      // false
isNumber(NaN)       // false
isNumber(Infinity)  // true

Design Principles

  • Zero dependencies — No external packages. The entire library adds minimal bundle impact.
  • Tree-shakeable — Import only what you use. Bundlers eliminate unused exports.
  • Fully typed — Generic types preserved through all transformations. No any types.
  • Immutable — Every function returns a new value. Inputs are never mutated.
  • Tested — Each function has comprehensive unit tests covering edge cases.

Bundle Size

ExportSize (gzipped)
groupBy~120B
pick / omit~90B each
slugify~180B
isNonNullable~30B
Full package~1.2KB

Note: This is a showcase entry demonstrating the package documentation template. The package structure and API design reflect real-world TypeScript utility patterns.