webhook/node_modules/type-fest
2024-03-28 12:25:32 +10:00
..
source chore: updating deps 2024-03-28 12:25:32 +10:00
index.d.ts update modules 2022-11-10 20:43:16 +10:00
license update modules 2022-11-10 20:43:16 +10:00
package.json chore: updating deps 2024-03-28 12:25:32 +10:00
readme.md chore: updating deps 2024-03-28 12:25:32 +10:00



type-fest

A collection of essential TypeScript types







npm dependents npm downloads

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.4

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 - Create a type that strips readonly from all or some of an object's keys. 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.
  • ValueOf - Create a union of the given object's values, and optionally specify which keys to get the values from.
  • PromiseValue - Returns the type that is wrapped inside a Promise.
  • AsyncReturnType - Unwrap the return type of a function that returns a Promise.
  • ConditionalKeys - Extract keys from a shape where values extend the given Condition type.
  • ConditionalPick - Like Pick except it selects properties from a shape where the values extend the given Condition type.
  • ConditionalExcept - Like Omit except it removes properties from a shape where the values extend the given Condition type.
  • UnionToIntersection - Convert a union type to an intersection type.
  • Stringified - Create a type with the keys of the given type changed to string type.
  • FixedLengthArray - Create a type that represents an array of the given type and length.
  • IterableElement - Get the element type of an Iterable/AsyncIterable. For example, an array or a generator.
  • Entry - Create a type that represents the type of an entry of a collection.
  • Entries - Create a type that represents the type of the entries of a collection.
  • SetReturnType - Create a function type with a return type of your choice and the same parameters as the given function type.
  • Asyncify - Create an async version of the given function type.

Template literal types

Note: These require TypeScript 4.1 or newer.

  • CamelCase Convert a string literal to camel-case (fooBar).
  • KebabCase Convert a string literal to kebab-case (foo-bar).
  • PascalCase Converts a string literal to pascal-case (FooBar)
  • SnakeCase Convert a string literal to snake-case (foo_bar).
  • DelimiterCase Convert a string literal to a custom string delimiter casing.
  • Get - Get a deeply-nested property from an object using a key path, like Lodash's .get() function.

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.
  • SubType - The type is powerful, but lacks good use-cases and is prone to misuse.
  • ExtractProperties and ExtractMethods - The types violate the single responsibility principle. Instead, refine your types into more granular type hierarchies.

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
    		};
    
    		private updateConfig<Key extends keyof NodeConfig>(key: Key, value: NodeConfig[Key]) {
    				this.configuration[key] = value;
    		}
    
    		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.updateConfig(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 the `Article` interface composed
    // from the 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 a collection of Employees 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 = (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<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 changing the 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', '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

    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 the type of the 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

    /** Provides every element of the iterable `iter` into the `callback` function and stores the 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, (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

    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 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<Animal, 'images' | 'paragraphs'>;
    
    function renderAnimalHoverInfo (animals: AnimalShortInfo[]): HTMLElement {
    		const container =  document.createElement('div');
    		// Internal implementation.
    		return container;
    }
    
  • Uppercase<S extends string> - Transforms every character in a string into uppercase.

    Example
    type T = Uppercase<'hello'>;  // 'HELLO'
    
    type T2 = Uppercase<'foo' | 'bar'>;  // 'FOO' | 'BAR'
    
    type T3<S extends string> = Uppercase<`aB${S}`>;
    type T4 = T30<'xYz'>;  // 'ABXYZ'
    
    type T5 = Uppercase<string>;  // string
    type T6 = Uppercase<any>;  // any
    type T7 = Uppercase<never>;  // never
    type T8 = Uppercase<42>;  // Error, type 'number' does not satisfy the constraint 'string'
    
  • Lowercase<S extends string> - Transforms every character in a string into lowercase.

    Example
    type T = Lowercase<'HELLO'>;  // 'hello'
    
    type T2 = Lowercase<'FOO' | 'BAR'>;  // 'foo' | 'bar'
    
    type T3<S extends string> = Lowercase<`aB${S}`>;
    type T4 = T32<'xYz'>;  // 'abxyz'
    
    type T5 = Lowercase<string>;  // string
    type T6 = Lowercase<any>;  // any
    type T7 = Lowercase<never>;  // never
    type T8 = Lowercase<42>;  // Error, type 'number' does not satisfy the constraint 'string'
    
  • Capitalize<S extends string> - Transforms the first character in a string into uppercase.

    Example
    type T = Capitalize<'hello'>;  // 'Hello'
    
    type T2 = Capitalize<'foo' | 'bar'>;  // 'Foo' | 'Bar'
    
    type T3<S extends string> = Capitalize<`aB${S}`>;
    type T4 = T32<'xYz'>;  // 'ABxYz'
    
    type T5 = Capitalize<string>;  // string
    type T6 = Capitalize<any>;  // any
    type T7 = Capitalize<never>;  // never
    type T8 = Capitalize<42>;  // Error, type 'number' does not satisfy the constraint 'string'
    
  • Uncapitalize<S extends string> - Transforms the first character in a string into lowercase.

    Example
    type T = Uncapitalize<'Hello'>;  // 'hello'
    
    type T2 = Uncapitalize<'Foo' | 'Bar'>;  // 'foo' | 'bar'
    
    type T3<S extends string> = Uncapitalize<`AB${S}`>;
    type T4 = T30<'xYz'>;  // 'aBxYz'
    
    type T5 = Uncapitalize<string>;  // string
    type T6 = Uncapitalize<any>;  // any
    type T7 = Uncapitalize<never>;  // never
    type T8 = Uncapitalize<42>;  // Error, type 'number' does not satisfy the constraint 'string'
    

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.