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
Primitive- Matches any primitive value.Class- Matches aclassconstructor.TypedArray- Matches any typed array, likeUint8ArrayorFloat64Array.JsonObject- Matches a JSON object.JsonArray- Matches a JSON array.JsonValue- Matches any valid JSON value.ObservableLike- Matches a value that is like an Observable.
Utilities
Except- Create a type from an object type without certain keys. This is a stricter version ofOmit.Mutable- Convert an object withreadonlyproperties into a mutable object. Inverse ofReadonly<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 aobject/Map/Set/Arraytype.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 inPromiseLike.Opaque- Create an opaque type.
Miscellaneous
PackageJson- Type for npm'spackage.jsonfile.
Declined types
If we decline a type addition, we will make sure to document the better solution here.
DiffandSpread- 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 inToptional.Example
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 inTrequired.Example
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 inTreadonly.Example
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>- FromT, pick a set of properties whose keys are in the unionK.Example
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 propertiesKof typeT.Example
// 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 fromTthose types that are assignable toU.Example
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 fromTthose types that are assignable toU.Example
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>- ExcludenullandundefinedfromT.Example
Works withstrictNullChecksset totrue. (Read more here)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
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
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
/** 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
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
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)
Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies.