npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

typey-doo

v0.6.1

Published

TypeScript Utility Types and Helper Functions

Downloads

31

Readme

CI NPM Downloads

It's typey-doo!

What it is?

typey-doo is a library of utility types and helper functions to help with your TypeScript projects. I doo declare!

What it do?

It doo a lot! As much as I need it to do in my own projects... And, probably more!

Algebraic Types — Any way you want it!

type: KeysOfUnion<U extends object>

Gets the union of keys of from a union of objects.

type Keys = KeysOfUnion<{ 'A': 0 }|{ 'B': 1 }|{ 'elephant': 2 }>
// type Keys = 'A'|'B'|'elephant

type: UnionToIntersection<U extends object>

Transforms a union of objects to an intersection of objects.

type I = UnionToIntersection<{ 'A': 0 }|{ 'B': 1 }|{ 'elephant': 2 }>
// type I = { 'A': 0 }&{ 'B': 1 }&{ 'elephant': 2 }

const i0: I = { 'A': 0, 'B': 1, 'elephant': 2 } // Ok!
const i1: I = { 'A': 1, 'B': 1, 'elephant': 2 } // Nope!
// Error: type 1 is not assignable to type 0

type: MergeIntersection<I extends object>

Combines an ugly intersection of object types into a single, beautiful object type.

type T = MergeIntersection<{ 'A': 0 }&{ 'B': 1 }&{ 'elephant': 2 }>
// type T = { 'A': 0, 'B': 1, 'elephant': 2 }

Much better!! Now I can sleep easy 😂zzzzz!

Boolean Algebra — Simply bootiful!

type: NOT<A extends boolean>

Negates a boolean.

type: AND<A extends boolean, B extends boolean>

AND's two booleans.

type: OR<A extends boolean, B extends boolean>

OR's two booleans.

type: XOR<A extends boolean, B extends boolean>

XOR's two booleans.

type: NAND<A extends boolean, B extends boolean>

NAND's two booleans.

type: NOR<A extends boolean, B extends boolean>

NOR's two booleans.

type: XNOR<A extends boolean, B extends boolean>

XNOR's two booleans.

Comparisons — I know right?!

type: Falsy<T>

Determines whether a type T is falsy.

type: Truthy<T>

Determines whether a type T is truthy.

type: Equal<U, V>

Performs a shallow check to determine whether types U and V have the same type.

type: AllEqual<T extends unknown[]>

Performs a shallow check to determine whether all elements of a given list T of types have the same type.

type: If<Cond extends boolean, A, B>

Evaluates to a type A if Cond has type true, or B when Cond has type false.

Errors — Oopsies!

type: AggregateErrorCtor<E extends AggregateError>

This type can be used in function signatures that expect a constructor for a subclass of AggregateError, without needing to extend the AggregateErrorConstructor interface.

See also:

type: ErrorCtor<E extends Error>

This type can be used in function signatures that expect a constructor for a subclass of Error, without needing to extend the ErrorConstructor interface.

See also:

type: IsError<T>

Evaluates to type true for any type T that extends Error, false otherwise.

type: IsAggregateError<T>

Evaluates to type true for any type T that extends AggregateError, false otherwise.

function: concatErrors<Ts extends Error[]>(errors: [...Ts], msg?: string): AggregateError

Takes a bunch o' errors and gives back an AggregateError.

let e0 = new TypeError('Oopsies!')

let e1 = new AggregateError([
    new Error('Something is wrong!'),
    new Error('Something else is wrong!')
  ], 'These happened together')

let e2 = new Error('The icing on the cake!')

let allMyErrors = concatErrors([e0, e1, e2], 'All my Errors in one place!')

console.dir(allMyErrors)
// AggregateError: All my errors in one place!
//   columnNumber: 5
//   errors: Array [ TypeError, AggregateError, Error ]
//   fileName: "debugger eval code"
//   lineNumber: 1
//   message: "All my errors in one place!"
//   stack: "@debugger eval code:1:5\n"
//   <prototype>: AggregateError.prototype { stack: "", _ }

function: fail<T extends string|Error|AggregateError, E extends Error>(err: T, ErrT: ErrorConstructor|ErrorCtor<E> = Error): never

A convenience function that allows errors to be thrown from within an expression:

definitelyNotUndefined ?? fail('it was undefined...')

With 2 overloads to choose from!

// 1st overload: function fail(err: Error | AggregateError): never
fail(new MyErrorType('Throw me!'))
fail(new MyAggregateErrorType([...], 'Throw us!'))

// 2nd overload: function fail<E extends Error>(msg: string, ErrT?: ErrorConstructor|ErrorCtor<T>): never
fail("Don't make me work for you!")
fail('...but do it my way!!', MyErrorType)

Expectations — We've all got 'em!

type: Expect<Expected, Actual>

Gives the expected type back when Expected and Actual are the same, otherwise never.

type: ExpectTrue<Actual>

Gives the type true back when Actual has type true, otherwise never.

type: ExpectFalse<Actual>

Gives the type false back when Actual has type false, otherwise never.

type: ExpectEqual<A, B>

Behaves like Equal, giving the type true back when types A and B are of the same type. However, when A and B are of differing types, behaves like Expect, giving back never.

Tuples — It's tuples all the way down!

type: Concat<A extends unknown[], B extends unknown []>

Concatenates a pair of tupes A and B.

type: Drop<T extends unknown[]>

Evaluates to the tuple matching T but with the last element removed.

Aliases: OmitLast

type: Head<T extends unknown[]>

Evaluates to the type of the first element of T when T is a nonempty tuple, otherwise undefined.

type: Last<T extends unknown[]>

Evaluates to the type of the last element of T when T is a nonempty tuple, otherwise undefined.

type: Tail<T extends unknown[]>

Evaluates to the tuple matching T but with the first element removed.

Aliases: Rest, OmitFirst

type: FindIndex<V, T extends unknown[]>

Finds the index of an element V in tuple T, or never if not found.

type: Filter<V, T extends unknown[]>

Filters any elements of type V from tuple T.

type: Repeat<V, N extends number>

Generates a tuple of N occurrences of type V.

Nominals — A rose by any other name would fail to type check!

type: TaggedType<T extends string, U>

Creates a tagged type for a common underlying type.

type Seconds  = TaggedType<'Seconds', number>
type Meters   = TaggedType<'Meters', number>
type Velocity = TaggedType<'Meters/Second', number>

declare function getVelocity(d: Meters, t: Seconds): Velocity

// ...

const d: Meters  = ...
const t: Seconds = ...

const v0 = getVelocity(4, 2) // Error!
const v1 = getVelocity(t, d) // Error!
const v2 = getVelocity(d, t) // Ok!

function: to<T extends ...>(value: ValueType<T>): T

Casts a value of some type V to a tagged type of the same underlying type V.

const d: Meters  = to<Meters>(4)
const t: Seconds = to<Seconds>(2)

let x: number = 9000
x = d // Error!
x = t // Error!

function: fr<T extends ...>(value: T): ValueType<T>

Casts a tagged type back to its underlying type.

const d: Meters = ...

let x: number = 9000
x = d             // Error!
x = fr<Meters>(d) // Ok!
x = fr(d)         // Ok! TypeScript is smart enough to infer T

Objects — Pretty good. Dare I say, objectively good? I doo dare!

type: AllKeys<T extends unknown[]>

Gives the union of all keys from the elements of T.

type Keys = AllKeys<[{ 'a': 0 }, { 'b': 1 }, { 'elephant': 42 }]>
// type Keys = 'a' | 'b' | 'elephant'

type: AsObject<T extends unknown[]>

Takes a tuple type and converts it into an record type.

Use it like so:

const obj: AsObject<[ 'a', 'b', 'c' ]> = { 0: 'a', 1: 'b', 2: 'c' }

type: KeysOf<T extends object>

Maybe you wanted something more verbose than the keyof operator?!

type: Merge<T extends unknown[]>

Gives the intersection of the elements of T.

type T0 = Merge<[{ 'a': 0 }, { 'b': 1 }, { 'c': 2 }]>
// type T0 = { a: 0 } & { b: 1 } & { c: 2 }

const o1: T0 = { a: 0, b: 1, c: 2 }         // Ok!
const o2: T0 = { a: 0, b: 1, c: 2, x: 'y' } // Error!
const o3: T0 = { a: 0, b: 1 }               // Error!

type T1 = Merge<[{ a: 0 }, { a: 0, b: 1 }]> // Ok!
// type T1 = { a: 0 } & { a: 0, b: 1}

type T2 = Merge<[{ a: 0 }, { a: 1 }]>       // Nope!
// type T2 = never

type: ValuesOf<T extends object>

Gives a shallow union of value types of T.

type Vals = ValuesOf<{ 0: 'a', 1: 'b', 2: 'c', o: { x: 'y' }}>
// type Vals = 'a' | 'b' | 'c' | { x: 'y' }

Asertions — The key to being assertive!

function:

  • assert(cond, error?): asserts cond
  • assert(cond, message?, ErrT?): asserts cond

Asserts the thruthiness of cond, throwing either an optional error instance error, or a string message as either an instance of Error or an optionally specified error type ErrT.

License

MIT © Tristan Bayfield