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 🙏

© 2026 – Pkg Stats / Ryan Hefner

type-plus

v8.0.0

Published

Provides additional types for TypeScript.

Readme

type-plus

NPM version NPM downloads

Release Codecov

More than 200 type utilities for TypeScript for applications, library, and type-level programming.

What's new in 8.0

type-plus 8.0 is a major release. It needs TypeScript 5.4 or later, and Node.js 20 or later for the runtime functions. The main changes from 7.x:

  • Branching types take an options object ({ $then, $else, selection, exact, distributive }) instead of positional Then and Else parameters.
  • The XxxType filter types, the IsStrictXxx predicates and the numeric filter types are removed. Use the IsXxx predicates with { selection: 'filter' } or { exact: true }.
  • Equal, CanAssign and the Extend family are removed. Use IsEqual and Assignable.
  • The top-level Partial, Required, Pick and Omit move to ObjectPlus, and the other deprecated exports are removed.
  • canAssign(), the one-argument isType() and the assertType members are removed. assertType() requires a validator.
  • The *Plus namespaces are type-only. Import them with import type.
  • Several predicates now distribute over unions, and a few results changed.

Most of the upgrade is mechanical. The v7 to v8 migration guide lists every breaking change with a before and after example, including the changed results that a rename will not surface.

Table of Contents

  1. Table of Contents
  2. What's new in 8.0
  3. Installation
  4. What's in the package?
    1. Update organization
    2. Update documentation
  5. Assertion Function
  6. Type Guard
  7. Type Utilities
  8. Type Specific Utilities
    1. any
    2. Array
    3. Union
    4. bigint
    5. Boolean
    6. Function
    7. Never
    8. Null
    9. Number
    10. Numeric
    11. Object
    12. Promise
    13. String
    14. Symbol
    15. Tuple
    16. Undefined
    17. unknown
    18. void
  9. Testing Utilities
  10. Constant Types
  11. JSON Support
  12. Type manipulation
  13. Type Predicates
    1. Logical
  14. Math
  15. Utility Functions
  16. Nominal Types
  17. Functional Types
  18. Attribution
  19. Useful Tips
  20. Similar projects

Installation

npm install type-plus

yarn add type-plus

pnpm add type-plus

What's in the package?

With over 200 types in type-plus, it can become difficult to find the types you need.

Also, some types need to be updated as TypeScript continue to evolve.

Currently, we are updating type-plus with the following objective:

  • Update organization
  • Update documentation
  • Clean up and deprecate types
  • Require TypeScript 5.4 or later (breaking change in 8.0)

Update organization

Top-level exports of type-plus will contain types and functions that do not expect the input to be a specific type. For example,

  • isType() and testType()
  • Type filters and predicates such as IsAny or IsArray

It can also have types and functions for specific types if it is a common convention, or the is no ambiguity, or for backwards compatibility purpose.

Other type specific utilities will be added under their respective *Plus namespaces such as ArrayPlus.At or NumericPlus.IsPositive.

Update documentation

Each type and utility function in type-plus will be updated to include examples and tags to indicate its category and behavior.

Each tag has an associated icon:

  • 👽 alias: Alias of another type
  • 🚦 assertion: assertion function
  • 🔢 customizable: the behavior of the type is customizable.
  • 💀 deprecated: deprecated and will be removed soon
  • 🌪️ filter: a.k.a. parse These types perform some kind of test. If the input passes the test, the input is returned. Otherwise, it returns never
  • 🛡️ guard: type guard function
  • 💥 immediate: the effect of the type can be observed immediately during development
  • ㊙️ internal: the type is internal and should not be used directly
  • 🏃 runtime: the function has runtime effect
  • 🩳 shortcut: Shortcut or convenient types
  • 🧪 testing: the type or function are designed for test
  • ⚗️ transform: these types transforms the input to another category
  • 🧰 type util: types for building types
  • 🦴 utilities: provide various functionalities
  • 🎭 predicate: a.k.a. predicate or logical. These types perform some kind of test. If the input passes the test, it returns true or false

Assertion Function

assertType<T>(subject, validator, message?)

🚦 assertion, 🏃 runtime: throws a TypeError unless validator passes, and narrows subject to T. The throwing counterpart of isType(), for pre- and post-conditions.

assertType<string>(value, (v) => typeof v === 'string', 'value must be a string')
value // string

🗑️ changed in 8.0.0: the validator is required. The no-validator overload, the constructor overload, and the members (assertType.isX/noX/as/custom) are removed; they checked nothing at runtime. Use x satisfies T for a compile-time check, and testType in tests.

Type Guard

User-defined type guard functions is a function which its return type is specified as x is T.

isType()

🛡️ guard: a generic type guard function

🗑️ removed in 8.0.0: the one-argument form isType<T>(subject). Use subject satisfies T instead. isType(subject, validator) stays.

Type Utilities

IsEqual<A, B, $O>

🎭 predicate, 🔢 customizable: A and B are the same type.

IsNotEqual<A, B, $O>

🎭 predicate, 🔢 customizable: A and B are not the same type.

Equal and the old positional IsEqual/IsNotEqual/NotEqual were removed in 8.0.0.

Assignable<A, B, $O>

🎭 predicate, 🔢 customizable: A is assignable to B.

NotAssignable<A, B, $O>

🎭 predicate, 🔢 customizable: A is not assignable to B.

IsLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is a scalar literal.

IsNotLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is not a scalar literal.

IsEmptyObject<T, $O>

🎭 predicate, 🔢 customizable: T is the empty object type {}.

IsNotEmptyObject<T, $O>

🎭 predicate, 🔢 customizable: T is not the empty object type {}.

Extendable, NotExtendable, IsExtend, IsNotExtend, CanAssign, StrictCanAssign and IsAssign were removed in 8.0.0. Use Assignable / NotAssignable instead:

  • Extendable<A, B> → Assignable.$<A, B, { selection: 'filter' }>
  • NotExtendable<A, B> → NotAssignable.$<A, B, { selection: 'filter' }>
  • IsExtend<A, B, Then, Else> → Assignable.$<A, B, { $then: Then; $else: Else }>
  • IsNotExtend<A, B, Then, Else> → NotAssignable.$<A, B, { $then: Then; $else: Else }>
  • CanAssign<A, B> / IsAssign<A, B> → Assignable<A, B>
  • StrictCanAssign<A, B> → Assignable<A, B, { distributive: false }>

A typical usage is using Assignable with testType:

testType.false<Assignable<boolean, { a: string }>>(true)
testType.true<Assignable<{ a: string; b: number }, { a: string }>>(true)

any, unknown and never follow TypeScript's own assignability relation: any is assignable to everything but never and everything is assignable to any, unknown is assignable only to any and unknown, and never is assignable to everything.

testType.true<Assignable<any, number>>(true)
testType.true<Assignable<number, any>>(true)
testType.false<Assignable<unknown, number>>(true)
testType.true<Assignable<never, number>>(true)
Assignable<number | string, number, { distributive: false }> // false
Assignable<number | string, number | string, { distributive: false }> // true

🗑️ removed in 8.0.0: the canAssign<T>() function. It checked nothing at runtime:

| Removed | In a test | In code | | --- | --- | --- | | canAssign<T>()(v) | testType.canAssign<typeof v, T>(true) | v satisfies T | | canAssign<T>(false)(v) | testType.canAssign<typeof v, T>(false) | |

Type Specific Utilities

type-plus provides type checking utilities for every type.

Each type has at least 2 type checks. Using string as an example, there are IsString<T> and IsNotString<T>. The { selection: 'filter' } option returns T or never instead of true or false, and { exact: true } matches only the wide type.

Some types will have more checks, such as boolean has IsTrue<T> and IsFalse<T>.

You can learn more in their respective sections:

any

IsAny<T, $O>

🎭 predicate, 🔢 customizable: T is any.

IsNotAny<T, $O>

🎭 predicate, 🔢 customizable: T is not any.

IsAnyOrNever<T, $O>

🎭 predicate, 🔢 customizable: T is exactly any or exactly never.

IsNotAnyOrNever<T, $O>

🎭 predicate, 🔢 customizable: T is neither exactly any nor exactly never.

Array

IsArray<T, $O>

🎭 predicate, 🔢 customizable: T is an array, excluding tuple.

IsNotArray<T, $O>

🎭 predicate, 🔢 customizable: T is not an array, excluding tuple.

At<A, N>

🦴 utilities: the element of A at the positive or negative index N.

Head<T>

🦴 utilities, 🔢 customizable: the first entry of the tuple, or the element type of the array T.

Last<T>

🦴 utilities, 🔢 customizable: the last entry of the tuple, or the element type of the array T.

Filter<A, Criteria>

⚗️ transform: keeps the entries of A satisfying Criteria.

🗑️ removed in 8.0.0: KeepMatch — use Filter instead.

FindFirst<A, Criteria>

🦴 utilities, 🔢 customizable: the first entry of A matching Criteria.

FindLast<A, Criteria>

🦴 utilities, 🔢 customizable: the last entry of A matching Criteria.

Some<A, Criteria>

🎭 predicate, 🔢 customizable: any element of A matches Criteria.

PadStart<A, L, PadWith>

⚗️ transform: pads the start of A with PadWith up to length L.

Reverse<A>

⚗️ transform: reverses the order of A.

🗑️ removed in 8.0.0: Concat and ArrayPlus.Concat — use the spread tuple [...A, ...B] instead.

IntersectOfProps<A, K>

⚗️ transform: the intersection of the K properties of the elements of A.

🗑️ removed in 8.0.0: MapToProp — use IntersectOfProps instead.

UnionOfProps<A, K>

⚗️ transform: the union of the K properties of the elements of A.

🗑️ removed in 8.0.0: PropUnion — use UnionOfProps instead.

UnionOfValues<A>

⚗️ transform: the union of the value types in A.

ArrayPlus

🧰 namespace: the array types. Entries, ElementMatch, IndexAt, IsIndexOutOfBound, IsReadonly and SplitAt are array-only; CommonPropKeys, DropMatch, Filter, Find and PadStart are the array halves of the top-level types that dispatch on A['length']; At, FindLast and Some are the top-level types grouped here too; Reverse keeps a readonly input readonly.

literalArray(...items)

🏃 runtime, 🦴 utilities: an array whose items are narrowed to the provided literals.

reduceWhile(array, reducer, predicate, initial)

🏃 runtime, 🦴 utilities: reduce() with a predicate for early termination.

Union

IsUnion<T, $O>

🎭 predicate, 🔢 customizable: T is a union.

IsNotUnion<T, $O>

🎭 predicate, 🔢 customizable: T is not a union.

SubUnion<T, U>

🧰 type util: a union type constrained to a subset of the union T.

bigint

Full reference: Bigint.

IsBigint<T, $O>

🎭 predicate, 🔢 customizable: T is bigint or a bigint literal. With { exact: true }, only bigint itself.

IsNotBigint<T, $O>

🎭 predicate, 🔢 customizable: T is not bigint nor a bigint literal.

IsBigintLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is a bigint literal. bigint itself is not.

IsNotBigintLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is not a bigint literal.

Boolean

IsBoolean<T, $O>

🎭 predicate, 🔢 customizable: T is boolean, true or false.

IsNotBoolean<T, $O>

🎭 predicate, 🔢 customizable: T is not boolean.

IsTrue<T, $O>

🎭 predicate, 🔢 customizable: T is true.

IsNotTrue<T, $O>

🎭 predicate, 🔢 customizable: T is not true.

IsFalse<T, $O>

🎭 predicate, 🔢 customizable: T is false.

IsNotFalse<T, $O>

🎭 predicate, 🔢 customizable: T is not false.

Function

IsFunction<T, $O>

🎭 predicate, 🔢 customizable: T is Function or a function signature.

IsNotFunction<T, $O>

🎭 predicate, 🔢 customizable: T is neither Function nor a function signature.

AnyFunction<P, R>

🧰 type util: a constraint matching any function.

ExtractFunction<F>

⚗️ transform: the function signature of a composite type F.

extractFunction(fn)

🏃 runtime, 🦴 utilities: narrow fn to its function signature only.

inspect(value, inspector?)

🏃 runtime, 🦴 utilities: inspect a value and return it. The inspector defaults to console.dir().

Never

IsNever<T, $O>

🎭 predicate, 🔢 customizable: T is never.

IsNotNever<T, $O>

🎭 predicate, 🔢 customizable: T is not never.

Null

IsNull<T, $O>

🎭 predicate, 🔢 customizable: T is null.

IsNotNull<T, $O>

🎭 predicate, 🔢 customizable: T is not null.

HasNull<T, $O>

🎭 predicate, 🔢 customizable: T is null or a union containing null.

HasNoNull<T, $O>

🎭 predicate, 🔢 customizable: T is not null and not a union containing null.

Number

Full reference: Number and Numeric.

IsNumber<T, $O>

🎭 predicate, 🔢 customizable: T is number or a number literal. With { exact: true }, only number itself.

IsNotNumber<T, $O>

🎭 predicate, 🔢 customizable: T is not number nor a number literal.

IsNumberLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is a number literal. number itself is not.

IsNotNumberLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is not a number literal.

Numeric

Widens the number checks to number | bigint and adds the value-shape predicates. Full reference: Number and Numeric.

Numeric

👽 alias: number | bigint.

Zero

👽 alias: 0 | 0n.

IsNumeric<T, $O>

🎭 predicate, 🔢 customizable: T is number or bigint, literals included.

IsNotNumeric<T, $O>

🎭 predicate, 🔢 customizable: T is neither number nor bigint.

IsInteger<T, $O>

🎭 predicate, 🔢 customizable: T is an integer, bigint included. number resolves to boolean.

IsNotInteger<T, $O>

🎭 predicate, 🔢 customizable: T is not an integer.

IsPositive<T, $O>

🎭 predicate, 🔢 customizable: T is a positive numeric type, zero included. number and bigint resolve to boolean.

IsNotPositive<T, $O>

🎭 predicate, 🔢 customizable: T is not a positive numeric type.

IsNegative<T, $O>

🎭 predicate, 🔢 customizable: T is a negative numeric type. number and bigint resolve to boolean.

IsNotNegative<T, $O>

🎭 predicate, 🔢 customizable: T is not a negative numeric type.

On the six above, { exact: true } matches only the wide number and bigint, never a literal. The *Literal types below are the other half of that split: they match only literals, so IsPositive<number> is boolean while IsPositiveLiteral<number> is false.

IsIntegerLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is an integer literal, bigint literals included.

IsNotIntegerLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is not an integer literal.

IsPositiveLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is a positive numeric literal, zero included.

IsNotPositiveLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is not a positive numeric literal.

IsNegativeLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is a negative numeric literal.

IsNotNegativeLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is not a negative numeric literal.

StringToNumber<S, $O>

⚗️ transform: a string literal to a number literal, or $O['$fail'] when the string is not one.

StringToBigint<S, $O>

⚗️ transform: a string literal with the n suffix to a bigint literal, or $O['$fail'] when the string is not one.

StringToNumeric<S, $O>

⚗️ transform: a string literal to a number or bigint literal, or $O['$fail'] when the string is not one.

NumericToString<N>

⚗️ transform: a number or bigint literal to its string literal form, the inverse of all three casts above.

Object

filterKey()

🦴 utilities: type adjusted filter by key.

findKey()

🦴 utilities: type adjusted find by key.

forEachKey()

🦴 utilities: type adjusted for each by key.

HasKey<T, K>

🦴 utilities: predicate type checking T has key K.

hasKey()

🦴 utilities: function of HasKey.

HasNoKey<T, K, $O>

🎭 predicate, 🔢 customizable: K is not a key of T.

IsRecord<T, $O>

🎭 predicate, 🔢 customizable: T is a record and not an array.

IsNotRecord<T, $O>

🎭 predicate, 🔢 customizable: T is not a record, or is an array.

KeysWithDiffType<A, B>

🦴 utilities: the keys A and B share whose property types disagree.

mapKey()

🦴 utilities: type adjusted map by key.

RecordValue<R>

🦴 utilities: gets the value type Tfrom Record<any, T>

Video.

reduceByKey()

🦴 utilities: type adjusted reduce by key.

someKey()

🦴 utilities: type adjusted some by key.

SpreadRecord<A, B>

🦴 utilities: type for {...a, ...b} when both a and b are Record
for array, just do [...A, ...B].

Promise

AwaitedProp<T, V>

🦴 utilities: Awaited on specified props P in T.

isPromise<R>(subject: any)

🦴 utilities: isPromise() type guard.

MaybePromise<T>

🦴 utilities: Alias of T | Promise<T>.

🗑️ removed in 8.0.0: PromiseValue — use the built-in Awaited<T> instead.

PromiseValueMerge<P1, P2, ...P9>

🦴 utilities: Merge the values of multiple promises.

mapSeries()

🦴 utilities: Similar to bluebird.mapSeries() but works with async/await.

transformMaybePromise(value, transformer)

🦴 utilities: Apply the transformer to the value.
It is also exported under MaybePromise.transform().

String

IsString<T, $O>

🎭 predicate, 🔢 customizable: T is string or a string literal. With { exact: true }, only string itself.

IsNotString<T, $O>

🎭 predicate, 🔢 customizable: T is neither string nor a string literal.

IsStringLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is a string literal. With { exact: true }, template literals that do not reduce to one are excluded.

IsNotStringLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is not a string literal.

IsTemplateLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is a template literal.

IsNotTemplateLiteral<T, $O>

🎭 predicate, 🔢 customizable: T is not a template literal.

StringIncludes<Subject, Search>

🎭 predicate, 🔢 customizable: Subject includes Search.

StringSplit<S, Separator>

⚗️ transform: split S into a tuple of substrings.

StringPlus

🧰 type util: the string types whose names are too generic to sit on the top level.

Symbol

IsSymbol<T, $O>

🎭 predicate, 🔢 customizable: T is symbol.

IsNotSymbol<T, $O>

🎭 predicate, 🔢 customizable: T is not symbol.

Tuple

IsTuple<T, $O>

🎭 predicate, 🔢 customizable: T is a tuple, excluding array.

IsNotTuple<T, $O>

🎭 predicate, 🔢 customizable: T is not a tuple, excluding array.

CreateTuple<L, T>

🦴 utilities: a tuple of L elements of type T.

ToTuple<L, T, R>

㊙️ internal: the accumulator loop behind CreateTuple.

CommonPropKeys<T>

⚗️ transform: the property keys common to every element of T.

Tail<T>

⚗️ transform: every entry of the tuple T except the first.

DropFirst<T>

⚗️ transform: drops the first entry of the tuple T.

DropLast<T>

⚗️ transform: drops the last entry of the tuple T.

DropMatch<A, Criteria>

⚗️ transform: drops the entries of A matching Criteria.

DropNull<A>

⚗️ transform, 👽 alias: DropMatch<A, null>.

DropUndefined<A>

⚗️ transform, 👽 alias: DropMatch<A, undefined>.

DropNullable<A>

⚗️ transform, 👽 alias: DropMatch<A, null | undefined>.

TuplePlus

🧰 namespace: the tuple halves of the five top-level types that dispatch on A['length'] — CommonPropKeys, DropMatch, Filter, Find (behind FindFirst) and PadStart.

🗑️ removed in 8.0.0: the runtime drop() — no replacement. The DropMatch/DropFirst/... types stay.

Undefined

IsUndefined<T, $O>

🎭 predicate, 🔢 customizable: T is undefined.

IsNotUndefined<T, $O>

🎭 predicate, 🔢 customizable: T is not undefined.

HasUndefined<T, $O>

🎭 predicate, 🔢 customizable: T is undefined or a union containing undefined.

HasNoUndefined<T, $O>

🎭 predicate, 🔢 customizable: T is not undefined and not a union containing undefined.

unknown

IsUnknown<T, $O>

🎭 predicate, 🔢 customizable: T is exactly unknown.

IsNotUnknown<T, $O>

🎭 predicate, 🔢 customizable: T is not exactly unknown.

NotUnknownOr<T, $O>

🧰 type util: T when it is not unknown, otherwise $Unknown.

void

IsVoid<T, $O>

🎭 predicate, 🔢 customizable: T is void.

IsNotVoid<T, $O>

🎭 predicate, 🔢 customizable: T is not void.

HasVoid<T, $O>

🎭 predicate, 🔢 customizable: T is void or a union containing void.

HasNoVoid<T, $O>

🎭 predicate, 🔢 customizable: T is not void and not a union containing void.

Testing Utilities

type-plus provides some testing utilities to help you test your types. They are exported from the type-plus/testing entry, not from type-plus.

One of the key utilities is testType.

import { testType } from 'type-plus/testing'

testType.any<T>(true) // T is `any`
testType.equal<A, B>(true) // A is equal to B
testType.never<T>(false) // T is not `never`

To reuse a check across tests, extract it with the deferred form and assert it at the call site:

import { testType } from 'type-plus/testing'

function testMyType<T>() {
	return [testType.defer.string<T>(), testType.defer.not.never<T>()]
}

testType.assert(testMyType<'a'>())

You can learn more about them in the docs.

testType is the testing API for types. It belongs in test files: in code, use satisfies for a compile-time check, and isType() or assertType() with a validator for a runtime one.

The older helpers that overlapped it were removed in 8.0.0:

| Removed | In a test | In code | | --- | --- | --- | | canAssign<T>()(v) | testType.canAssign<typeof v, T>(true) | v satisfies T | | canAssign<T>(false)(v) | testType.canAssign<typeof v, T>(false) | | | isType<T>(v) (one argument) | testType.canAssign<typeof v, T>(true) | v satisfies T | | assertType<T>(v) (no validator) and its members | testType.* | v satisfies T, or assertType(v, validator) | | isType.t / .f / .never / .equal | testType.true / .false / .never / .equal | |

Constant Types

KeyTypes

👽 alias: type of all keys.

PrimitiveTypes

👽 alias: all primitive types, including Function, symbol, and bigint.

ComposableTypes

👽 alias: Types that can contain custom properties. i.e. object, array, function.

NonComposableTypes

👽 alias: Types that cannot contain custom properties. i.e. not composable.

JSON Support

Full reference: JSON.

JsonPrimitive

👽 alias: primitive types valid in JSON

JsonObject

👽 alias: JSON object. A key may be absent but never undefined.

JsonArray

👽 alias: JSON array, readonly so tuples and as const data are accepted.

JsonTypes

👽 alias: any value JSON.parse can produce.

JsonCompatible<T>

🧰 type util: constrain with T extends JsonCompatible<T> to accept any JSON-safe value, including an interface. The compiler error names the path of the part that is not JSON.

import type { JsonCompatible } from 'type-plus'

function save<T extends JsonCompatible<T>>(value: T) { ... }

interface Post { createdAt: Date }
save(post) // Type 'Date' is not assignable to type '"not JSON at $.createdAt"'

IsJson<T, $O>, IsNotJson<T, $O>

🎭 predicate: validate if T survives a JSON round trip.

Serialized<T, $O>, Deserialized<S>

🧰 type util: a string carrying the type of the value it was serialized from, and the type parsing it gives back. Two lines of wrapper give JSON or flatted a typed round trip. { circular: true } tags flatted's format, so the two formats do not mix.

import type { Deserialized, JsonCompatible, Serialized } from 'type-plus'

const stringify = <T extends JsonCompatible<T>>(value: T) => JSON.stringify(value) as Serialized<T>
const parse = <S extends Serialized<any>>(text: S) => JSON.parse(text) as Deserialized<S>

const user = parse(stringify({ id: 1, tags: ['a'] })) // { id: number; tags: string[] }

Type manipulation

ANotB<A, B>

🦴 utilities: get object with properties in A and not in B, including properties with a different value type.

BNotA<A, B>

🦴 utilities: flip of ANotB

as<T>(subject)

🦴 utilities: assert subject as T. Avoid ASI issues such as ;(x as T).abc

asAny(subject)

🦴 utilities: assert subject as any. Avoid ASI issue such as ;(x as any).abc

🗑️ removed in 8.0.0: EitherAnd — use EitherOrBoth instead.

EitherOrBoth<A, B, [C, D]>

🦴 utilities: combines 2 to 4 types as A | B | (A & B).

This is useful for combining options video.

🗑️ removed in 8.0.0: Except — use ObjectPlus.Omit instead.

ExcludePropType<T, U>

🦴 utilities: excludes type U from properties in T.

🗑️ removed in 8.0.0: KeysOfOptional — use OptionalKeys<T> for the optional keys, keyof T for the key union.

KnownKeys<T>

🦴 utilities: extract known (defined) keys from type T.

LeftJoin<A, B>

🦴 utilities: left join A with B

NonNullable<T> (TypeScript built-in)

🦴 utilities: removes null and undefined from T. type-plus no longer ships its own NonNull and NonUndefined; use the built-in, or IsNotNull / IsNotUndefined to test instead.

🗑️ removed in 8.0.0: the top-level Omit — use ObjectPlus.Omit instead.

ObjectPlus.Omit<T, K>

🦴 utilities: From T, pick a set of properties whose keys are not in the union K. This is the opposite of ObjectPlus.Pick<T, K>. Unlike the built-in Omit, it distributes over unions and rejects a key no member of T has.

OptionalKeys<T>

🦴 utilities: gets keys of optional properties in T.

🗑️ removed in 8.0.0: the top-level Partial — use ObjectPlus.Partial instead.

🗑️ removed in 8.0.0: PartialExcept — use PartialOmit instead.

PartialOmit<T, U>

🦴 utilities: makes the properties not specified in U becomes optional.

PartialPick<T, U>

🦴 utilities: makes the properties specified in U becomes optional.

🗑️ removed in 8.0.0: the top-level Pick — use ObjectPlus.Pick instead.

ObjectPlus.Pick<T, K>

🦴 utilities: pick properties K from T. Unlike the built-in Pick, it distributes over unions.

RecursivePartial<T>

🦴 utilities: make type T optional recursively.

RecursiveRequired<T>

🦴 utilities: make type T required recursively.

ReplaceProperty<T, K, V>

🦴 utilities: replace property K in T with V.

🗑️ removed in 8.0.0: the top-level Required — use ObjectPlus.Required instead.

RequiredKeys<T>

🦴 utilities: gets keys of required properties in T.

RequiredPick<T, U>

🦴 utilities: makes the properties specified in U become required.

RequiredOmit<T, U>

🦴 utilities: makes the properties not specified in U become required.

💀 deprecated since 8.0.0: RequiredExcept — use RequiredOmit instead.

RecursiveIntersect<T, U>

🦴 utilities: intersect type U onto T recursively.

ValueOf<T>

🦴 utilities: type of the value of the properties of T.

Widen<T>

🦴 utilities: widen literal types.

PropType

💀 ...no helper type for this. Just do YourType['propName'].

Type Predicates

Type predicates are type alias that returns true or false. They can be used to compose complex types.

HasKey<T, K>

🦴 utilities: predicate type checking T has key K.

IsAny<T>

🦴 utilities: T === any.

IsBoolean<T>

🦴 utilities: check for boolean, but not for true nor false.

IsDisjoint<A, B, $O>

🎭 predicate, 🔢 customizable: A and B share no key.

IsEmptyObject<T, $O>

🎭 predicate, 🔢 customizable: T is the empty object type {}.

IsLiteral<T>

🦴 utilities: is T a literal type (literal string or number).

Logical

If<Condition, $O>

🎭 predicate, 🔢 customizable: selects the $then branch when Condition is true, the $else branch otherwise.

And<A, B, $O>

🎭 predicate, 🔢 customizable: logical AND.

Or<A, B, $O>

🎭 predicate, 🔢 customizable: logical OR.

Xor<A, B, $O>

🎭 predicate, 🔢 customizable: logical XOR.

Not<X, $O>

🎭 predicate, 🔢 customizable: logical NOT.

Note that these types work correctly with the boolean type. e.g.:

type R = And<boolean, true> // boolean
type R = Not<boolean>       // boolean

There is a problem with generic distribution: https://github.com/microsoft/TypeScript/issues/41053 So you may encounter some weird behavior if your logic is complex.

Math

The math types in type-plus works with most numeric types.

It works with number and bigint, positive and negative number, including floating point numbers.

It will cast the type between number and bigint if needed.

Abs<N, $O>

🦴 utilities: Abs(N).

Max<A, B, $O>

🦴 utilities: max(A, B)

Min<A, B, $O>

🦴 utilities: min(A, B)

GreaterThan<A, B>

🦴 utilities: A > B.

GreaterThanOrEqual<A, B>

🦴 utilities: A >= B.

LessThan<A, B>

🦴 utilities: A < B.

LessThanOrEqual<A, B>

🦴 utilities: A <= B.

Add<A, B>

🦴 utilities: A + B.

Subtract<A, B>

🦴 utilities: A > B.

Increment<A>

🦴 utilities: alias of Add<A, 1>.

Decrement<A>

🦴 utilities: alias of Subtract<A, 1>.

Multiply<A, B

🦴 utilities: A * B.

Divide<A, B>

🦴 utilities: A / B, truncated toward zero to 16 fractional digits by default.

Quotient<A, B>

🦴 utilities: integer A / B, truncated toward zero.

Remainder<A, B>

🦴 utilities: A % B on integers.

Utility Functions

amend(subject)...

🦴 utilities: amend subject as union or intersect of T.

facade(subject, ...props)

🦴 utilities: create a facade of subject.

getField(subject, key, defaultValue)

🦴 utilities: get a field from a subject. Works against nullable and optional subject.

hasKey()

🦴 utilities: function of HasKey.

hasProperty(value, prop)

🦴 utilities: assert value has property prop. This will pick the correct union type.

🗑️ removed in 8.0.0: isConstructor — no replacement. It was not a failsafe test: it returned true for any function that can be called with new. AnyConstructor stays.

isSystemError(code, err)

🦴 utilities: type guard err with NodeJS error code.

omit(obj, ...props)

🦴 utilities: omit properties from obj.

pick(obj, ...props)

🦴 utilities: pick properties from obj.

record<K, V>(value?)

🦴 utilities: create a Record<K, V> without extra object prototype.

record<R>(value?)

🦴 utilities: create a record R (e.g. { a: number }) without extra object prototype.

required(...)

🦴 utilities: merge up to three partial objects shallowly, left to right. A later undefined overwrites. From unpartial

requiredDeep(...)

🦴 utilities: merge up to three partial objects recursively, left to right. A later undefined keeps the earlier value, and a later array replaces the earlier one. From unpartial

split(target, ...splitters)

🦴 utilities: split one object into multiple objects.

stub<T>(value)

🦴 utilities: stub a particular type T. Imported from type-plus/testing.

stub.build<T>(init?)

🦴 utilities: build a stub for particular type T. Imported from type-plus/testing.

typeOverrideIncompatible<T>()

🦴 utilities: override only the incompatible portion between two types.

type A =  {
  foo: boolean,
  bar: string,
  baz: string
}

const overrider = typeOverrideIncompatible<A>()
const source = {
  foo: 1,
  bar: 'bar',
  baz: 'baz'
}

// only the `foo` property is available to override.
overrider(source, { foo: !!source.foo })

🗑️ removed in 8.0.0: unpartial() re-export — import it from the unpartial package directly.

context()

🦴 utilities: a context builder.

This is useful to build context for functional programming. It is a sync version of the AsyncContext from async-fp.

import { context } from 'type-plus'

// { a: 1, b: 2 }
const ctx = context({ a: 1 })
  .extend(c => ({ b: c.a + 1 }))
  .build()

Nominal Types

The TypeScript type system is structural.

In some cases, we want to express a type with nominal behavior. type-plus provides two kinds of nominal types: Brand and Flavor.

Brand<B, T>:

brand(type, subject?):

Branded nominal type is the stronger nominal type of the two. It disallows unbranded type assigned to it:

const a = brand('a', { a: 1 })
const b = { a: 1 }
a = b // error

subject can be any type, from primitive to strings to objects.

brand(type):

If you do not provide subject, brand(type) will return a brand creator, so that you can use it to create multiple branded values:

const nike = brand('nike')
const shirt = nike('shirt')
const socks = nike('socks')

Flavor<F, T>:

flavor(type, subject?):

The key difference between Flavor and Brand is that unflavored type can be assigned to Flavor:

let f = flavor('orange', 'soda')
f = 'mist' // ok

Also, Brand of the same name can be assigned to Flavor, but Flavor of the same name cannot be assigned to Brand.

nominalMatch(a, b):

🦴 utilities: compare if the two values are nominally equal.

Works with both Brand and Flavor.

const b1 = brand('x', 1)
const b2 = brand('y', 1)

nominalMatch(b1, b2) // false

Functional Types

ChainFn<T>: T

🦴 utilities: chain function that returns the input type.

compose(...fns): F

🦴 utilities: compose functions

Attribution

Some code in this library is created by other people in the TypeScript community. I'm merely adding them in and maybe making some adjustments. Whenever possible, I add attribution to the person who created those codes in the file.

Useful Tips

https://github.com/microsoft/TypeScript/wiki/Performance

Similar projects

  • expect-type: Compile-time tests for types
  • hotscript: Higher-order TypeScript
  • spec.ts: write tests for your types!
  • ts-calc: compute with typescript type system, part of hotscript
  • ts-essentials: all essential TypeScript types in one place.
  • ts-expect: Checks values in TypeScript match expectations.
  • ts-toolbelt: TypeScript's largest utility library.
  • type-fest: a collection of essential TypeScript types.
  • type-zoo: a modest type lib usable today.
  • typepark: a new type collection offering tuple manipulation and Pipe.
  • typelevel-ts: a type lib by @gcanti, author of several FP libraries in TS.
  • typical: a playground of type-level operations for TypeScript.
  • utility-types: collection of utility types, complementing TypeScript built-in mapped types and aliases.
  • earl: Ergonomic, modern and type-safe assertion library for TypeScript