Skip to content

Readme



type-fest

A collection of essential TypeScript types



Build Status

Many of the types here should have been built-in. You can help by suggesting some of them to the TypeScript project.

Either add this package as a dependency or copy-paste the needed types. No credit required. 👌

PR welcome for additional commonly needed types and docs improvements. Read the contributing guidelines first.

Install

$ npm install type-fest

Requires TypeScript >=3.2

Usage

import {Except} from 'type-fest';

type Foo = {
    unicorn: string;
    rainbow: boolean;
};

type FooWithoutRainbow = Except<Foo, 'rainbow'>;
//=> {unicorn: string}

API

Click the type names for complete docs.

Basic

Utilities

  • Except - Create a type from an object type without certain keys. This is a stricter version of Omit.
  • Mutable - Convert an object with readonly keys into a mutable object. The inverse of Readonly<T>.
  • Merge - Merge two types into a new type. Keys of the second type overrides keys of the first type.
  • MergeExclusive - Create a type that has mutually exclusive keys.
  • RequireAtLeastOne - Create a type that requires at least one of the given keys.
  • RequireExactlyOne - Create a type that requires exactly a single key of the given keys and disallows more.
  • PartialDeep - Create a deeply optional version of another type. Use Partial<T> if you only need one level deep.
  • ReadonlyDeep - Create a deeply immutable version of an object/Map/Set/Array type. Use Readonly<T> if you only need one level deep.
  • LiteralUnion - Create a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union. Workaround for Microsoft/TypeScript#29729.
  • Promisable - Create a type that represents either the value or the value wrapped in PromiseLike.
  • Opaque - Create an opaque type.
  • SetOptional - Create a type that makes the given keys optional.
  • SetRequired - Create a type that makes the given keys required.

Miscellaneous

Declined types

If we decline a type addition, we will make sure to document the better solution here.

  • Diff and Spread - The PR author didn't provide any real-world use-cases and the PR went stale. If you think this type is useful, provide some real-world use-cases and we might reconsider.
  • Dictionary - You only save a few characters (Dictionary<number> vs Record<string, number>) from Record, which is more flexible and well-known. Also, you shouldn't use an object as a dictionary. We have Map in JavaScript now.

Tips

Built-in types

There are many advanced types most users don't know about.

  • Partial<T> - Make all properties in T optional.

    Example

    Playground

    ```ts interface NodeConfig { appName: string; port: number; }

    class NodeAppBuilder { private configuration: NodeConfig = { appName: 'NodeApp', port: 3000 };

        config(config: Partial<NodeConfig>) {
                type NodeConfigKey = keyof NodeConfig;
    
                for (const key of Object.keys(config) as NodeConfigKey[]) {
                        const updateValue = config[key];
    
                        if (updateValue === undefined) {
                                continue;
                        }
    
                        this.configuration[key] = updateValue;
                }
    
                return this;
        }
    

    }

    // `Partial`` allows us to provide only a part of the // NodeConfig interface. new NodeAppBuilder().config({appName: 'ToDoApp'}); ```

  • Required<T> - Make all properties in T required.

    Example

    Playground

    ```ts interface ContactForm { email?: string; message?: string; }

    function submitContactForm(formData: Required) { // Send the form data to the server. }

    submitContactForm({ email: 'ex@mple.com', message: 'Hi! Could you tell me more about…', });

    // TypeScript error: missing property 'message' submitContactForm({ email: 'ex@mple.com', }); ```

  • Readonly<T> - Make all properties in T readonly.

    Example

    Playground

    ```ts enum LogLevel { Off, Debug, Error, Fatal };

    interface LoggerConfig { name: string; level: LogLevel; }

    class Logger { config: Readonly;

        constructor({name, level}: LoggerConfig) {
                this.config = {name, level};
                Object.freeze(this.config);
        }
    

    }

    const config: LoggerConfig = { name: 'MyApp', level: LogLevel.Debug };

    const logger = new Logger(config);

    // TypeScript Error: cannot assign to read-only property. logger.config.level = LogLevel.Error;

    // We are able to edit config variable as we please. config.level = LogLevel.Error; ```

  • Pick<T, K> - From T, pick a set of properties whose keys are in the union K.

    Example

    Playground

    ```ts interface Article { title: string; thumbnail: string; content: string; }

    // Creates new type out of the Article interface composed // from the Articles' two properties: title and thumbnail. // ArticlePreview = {title: string; thumbnail: string} type ArticlePreview = Pick;

    // Render a list of articles using only title and description. function renderArticlePreviews(previews: ArticlePreview[]): HTMLElement { const articles = document.createElement('div');

        for (const preview of previews) {
                // Append preview to the articles.
        }
    
        return articles;
    

    }

    const articles = renderArticlePreviews([ { title: 'TypeScript tutorial!', thumbnail: '/assets/ts.jpg' } ]); ```

  • Record<K, T> - Construct a type with a set of properties K of type T.

    Example

    Playground

    ```ts // Positions of employees in our company. type MemberPosition = 'intern' | 'developer' | 'tech-lead';

    // Interface describing properties of a single employee. interface Employee { firstName: string; lastName: string; yearsOfExperience: number; }

    // Create an object that has all possible MemberPosition values set as keys. // Those keys will store a collection of Employees of the same position. const team: Record = { intern: [], developer: [], 'tech-lead': [], };

    // Our team has decided to help John with his dream of becoming Software Developer. team.intern.push({ firstName: 'John', lastName: 'Doe', yearsOfExperience: 0 });

    // Record forces you to initialize all of the property keys. // TypeScript Error: "tech-lead" property is missing const teamEmpty: Record = { intern: null, developer: null, }; ```

  • Exclude<T, U> - Exclude from T those types that are assignable to U.

    Example

    Playground

    ```ts interface ServerConfig { port: null | string | number; }

    type RequestHandler = (request: Request, response: Response) => void;

    // Exclude null type from null | string | number. // In case the port is equal to null, we will use default value. function getPortValue(port: Exclude): number { if (typeof port === 'string') { return parseInt(port, 10); }

    return port;
    

    }

    function startServer(handler: RequestHandler, config: ServerConfig): void { const server = require('http').createServer(handler);

    const port = config.port === null ? 3000 : getPortValue(config.port);
    server.listen(port);
    

    } ```

  • Extract<T, U> - Extract from T those types that are assignable to U.

    Example

    Playground

    ```ts declare function uniqueId(): number;

    const ID = Symbol('ID');

    interface Person { [ID]: number; name: string; age: number; }

    // Allows changing the person data as long as the property key is of string type. function changePersonData< Obj extends Person, Key extends Extract, Value extends Obj[Key]

    (obj: Obj, key: Key, value: Value): void { obj[key] = value; }

    // Tiny Andrew was born. const andrew = { [ID]: uniqueId(), name: 'Andrew', age: 0, };

    // Cool, we're fine with that. changePersonData(andrew, 'name', 'Pony');

    // Goverment didn't like the fact that you wanted to change your identity. changePersonData(andrew, ID, uniqueId()); ```

  • NonNullable<T> - Exclude null and undefined from T.

    Example Works with strictNullChecks set to true. (Read more here)

    Playground

    ```ts type PortNumber = string | number | null;

    /* Part of a class definition that is used to build a server / class ServerBuilder { portNumber!: NonNullable;

        port(this: ServerBuilder, port: PortNumber): ServerBuilder {
                if (port == null) {
                        this.portNumber = 8000;
                } else {
                        this.portNumber = port;
                }
    
                return this;
        }
    

    }

    const serverBuilder = new ServerBuilder();

    serverBuilder .port('8000') // portNumber = '8000' .port(null) // portNumber = 8000 .port(3000); // portNumber = 3000

    // TypeScript error serverBuilder.portNumber = null; ```

  • Parameters<T> - Obtain the parameters of a function type in a tuple.

    Example

    Playground

    ```ts function shuffle(input: any[]): void { // Mutate array randomly changing its' elements indexes. }

    function callNTimes any> (func: Fn, callCount: number) { // Type that represents the type of the received function parameters. type FunctionParameters = Parameters;

    return function (...args: FunctionParameters) {
        for (let i = 0; i < callCount; i++) {
            func(...args);
        }
    }
    

    }

    const shuffleTwice = callNTimes(shuffle, 2); ```

  • ConstructorParameters<T> - Obtain the parameters of a constructor function type in a tuple.

    Example

    Playground

    ```ts class ArticleModel { title: string; content?: string;

    constructor(title: string) {
        this.title = title;
    }
    

    }

    class InstanceCache any)> { private ClassConstructor: T; private cache: Map> = new Map();

    constructor (ctr: T) {
        this.ClassConstructor = ctr;
    }
    
    getInstance (...args: ConstructorParameters<T>): InstanceType<T> {
        const hash = this.calculateArgumentsHash(...args);
    
        const existingInstance = this.cache.get(hash);
        if (existingInstance !== undefined) {
            return existingInstance;
        }
    
        return new this.ClassConstructor(...args);
    }
    
    private calculateArgumentsHash(...args: any[]): string {
        // Calculate hash.
        return 'hash';
    }
    

    }

    const articleCache = new InstanceCache(ArticleModel); const amazonArticle = articleCache.getInstance('Amazon forests burining!'); ```

  • ReturnType<T> – Obtain the return type of a function type.

    Example

    Playground

    ``ts /** Provides every element of the iterableiterinto thecallback` function and stores the results in an array. */ function mapIter< Elem, Func extends (elem: Elem) => any, Ret extends ReturnType

    (iter: Iterable, callback: Func): Ret[] { const mapped: Ret[] = [];

        for (const elem of iter) {
                mapped.push(callback(elem));
        }
    
        return mapped;
    

    }

    const setObject: Set = new Set(); const mapObject: Map = new Map();

    mapIter(setObject, (value: string) => value.indexOf('Foo')); // number[]

    mapIter(mapObject, ([key, value]: [number, string]) => { return key % 2 === 0 ? value : 'Odd'; }); // string[] ```

  • InstanceType<T> – Obtain the instance type of a constructor function type.

    Example

    Playground

    ```ts class IdleService { doNothing (): void {} }

    class News { title: string; content: string;

        constructor(title: string, content: string) {
                this.title = title;
                this.content = content;
        }
    

    }

    const instanceCounter: Map = new Map();

    interface Constructor { new(...args: any[]): any; }

    // Keep track how many instances of Constr constructor have been created. function getInstance< Constr extends Constructor, Args extends ConstructorParameters

    (constructor: Constr, ...args: Args): InstanceType { let count = instanceCounter.get(constructor) || 0;

        const instance = new constructor(...args);
    
        instanceCounter.set(constructor, count + 1);
    
        console.log(`Created ${count + 1} instances of ${Constr.name} class`);
    
        return instance;
    

    }

    const idleService = getInstance(IdleService); // Will log: Created 1 instances of IdleService class const newsEntry = getInstance(News, 'New ECMAScript proposals!', 'Last month...'); // Will log: Created 1 instances of News class ```

  • Omit<T, K> – Constructs a type by picking all properties from T and then removing K.

    Example

    Playground

    ```ts interface Animal { imageUrl: string; species: string; images: string[]; paragraphs: string[]; }

    // Creates new type with all properties of the Animal interface // except 'images' and 'paragraphs' properties. We can use this // type to render small hover tooltip for a wiki entry list. type AnimalShortInfo = Omit;

    function renderAnimalHoverInfo (animals: AnimalShortInfo[]): HTMLElement { const container = document.createElement('div'); // Internal implementation. return container; } ```

You can find some examples in the TypeScript docs.

Maintainers

License

(MIT OR CC0-1.0)


Get professional support for this package with a Tidelift subscription
Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies.