2019-09-14 11:52:11 +07:00
2019-09-10 16:46:21 +07:00
2019-06-14 15:15:38 +07:00
2019-08-03 15:53:02 +02:00
2019-08-03 15:30:30 +02:00
2019-03-13 17:38:21 +07:00
2019-03-13 17:38:21 +07:00
2019-03-13 17:38:21 +07:00
2019-03-13 17:38:21 +07:00
2019-06-07 14:31:22 +07:00
2019-03-13 17:38:21 +07:00
2019-03-13 17:38:21 +07:00
2019-08-03 15:53:51 +02:00
2019-03-13 17:38:21 +07:00



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 properties into a mutable object. 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 properties.
  • RequireAtLeastOne - Create a type that requires at least one of the given properties.
  • ReadonlyDeep - Create a deeply immutable version of a object/Map/Set/Array type.
  • 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.

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.

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

    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<NodeConfig> 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

    interface ContactForm {
        email?: string;
        message?: string;
    }
    
    function submitContactForm (formData: Required<ContactForm>) {
        // 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

    enum LogLevel {
        Off,
        Debug,
        Error,
        Fatal,
    };
    
    interface LoggerConfig {
        name: string;
        level: LogLevel;
    }
    
    class Logger {
        config: Readonly<LoggerConfig>;
    
        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

    interface Article {
        title: string;
        thumbnail: string;
        content: string;
    }
    
    // Creates new type out of Article interface composed from Articles' two
    // properties: 'title' and 'thumbnail'.
    // ArticlePreview = { title: string; thumbnail: string; }
    type ArticlePreview = Pick<Article, 'title' | 'thumbnail'>;
    
    // 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

        // 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 collection of Emplyees of the same position.
    const team: Record<MemberPosition, Employee[]> = {
        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<MemberPosition, null> = {
        intern: null,
        developer: null,
    };
    
  • Exclude<T, U> - Exclude from T those types that are assignable to U.

    Example

    Playground

    interface ServerConfig {
      port: null | string | number;
    }
    
    type RequestHandler = (req: Request, res: Response) => void;
    
    // Exclude null type from `null | string | number`.
    // In case when port is equal to null we will use default value.
    function getPortValue(port: Exclude<ServerConfig['port'], null>): 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

    declare function uniqueId(): number;
    const ID = Symbol('ID');
    
    interface Person {
      [ID]: number;
      name: string;
      age: number;
    }
    
    // Allows change of person data as long as the property key is of string type.
    function changePersonData<
      Obj extends Person,
      Key extends Extract<keyof Person, string>,
      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', 'Andrea');
    
    // 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

    type PortNumber = string | number | null;
    
    /** Part of a class definition that is used to build a server */
    class ServerBuilder {
        portNumber!: NonNullable<PortNumber>;
    
        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

    function shuffle(input: any[]): void {
      // Mutate array randomly changing its' elements indexes.
    }
    
    function callNTimes<Fn extends (...args: any[]) => any> (func: Fn, callCount: number) {
      // Type that represents type of received function parameters.
      type FunctionParameters = Parameters<Fn>;
    
      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

    class ArticleModel {
      title: string;
      content?: string;
    
      constructor(title: string) {
        this.title = title;
      }
    }
    
    class InstanceCache<T extends (new (...args: any[]) => any)> {
      private ClassConstructor: T;
      private cache: Map<string, InstanceType<T>> = 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

    /** Provide every element of iterable `iter` into the `callback` function and store results in an array. */
    function mapIter<
        Elem,
        Func extends (elem: Elem) => any,
        Ret extends ReturnType<Func>
    >(iter: Iterable<Elem>, callback: Func): Ret[] {
        const mapped: Ret[] = [];
    
        for (const elem of iter) {
            mapped.push(callback(elem));
        }
    
        return mapped;
    }
    
    const setObject: Set<string> = new Set();
    const mapObject: Map<number, string> = new Map();
    
    mapIter(setObject, (v: string) => v.indexOf('Foo')); // number[]
    
    mapIter(mapObject, ([key, val]: [number, string]) => {
        return key % 2 === 0 ? val : 'Odd';
    }); // string[]
    
  • InstanceType<T> Obtain the instance type of a constructor function type.

    Example

    Playground

    class IdleService {
        doNothing (): void {}
    }
    
    class News {
        title: string;
        content: string;
    
        constructor(title: string, content: string) {
            this.title = title;
            this.content = content;
        }
    }
    
    const instanceCounter: Map<Function, number> = 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<Constr>
    >(constructor: Constr, ...args: Args): InstanceType<Constr> {
        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

    interface Animal {
        imageUrl: string;
        species: string;
        images: string[];
        paragraphs: string[];
    }
    
    // Creates new type with all properties of Animal interface except 'images' and
    // 'paragraphs' properties.
    // We can use this type to render small hover tooltip for Wiki entry list.
    type AnimalShortInfo = Omit<Animal, 'images' | 'paragraphs'>;
    
    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.
Description
A collection of essential TypeScript types
Readme 9.5 MiB
Languages
TypeScript 86.9%
JavaScript 13.1%