sfcode An Online Competing and Development Environment

readme

Example

A collection of essential TypeScript types

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 a `class` constructor.
- `TypedArray` - Matches any typed array, like `Uint8Array` or `Float64Array`.
- `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 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.
- `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.

### Miscellaneous

- `PackageJson` - Type for npm's `package.json` file.
- `TsConfigJson` - Type for TypeScript's `tsconfig.json` file (TypeScript 3.7).

## 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. <details>

Playground

```ts 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'}); ``` </details>

- `Required<T>` - Make all properties in `T` required. <details>

Example

Playground

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

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

submitContactForm({ email: 'ex@mp.nosp@m.le.c.nosp@m.om', message: 'Hi! Could you tell me more about…', });

// TypeScript error: missing property 'message' submitContactForm({ email: 'ex@mp.nosp@m.le.c.nosp@m.om', }); ``` </details>

- `Readonly<T>` - Make all properties in `T` readonly. <details>

Example

Playground

```ts 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; ``` </details>

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

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<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' } ]); ``` </details>

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

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<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, }; ``` </details>

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

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<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); } ``` </details>

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

Example

Playground

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

const ID = Symbol('ID');

interface Person {

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 = {

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()); ``` </details>

- `NonNullable<T>` - Exclude `null` and `undefined` from `T`. <details>

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<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; ``` </details>

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

Example

Playground

```ts 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); ``` </details>

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

Example

Playground

```ts 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!'); ``` </details>

- `ReturnType<T>` – Obtain the return type of a function type. <details>

Example

Playground

```ts /** 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[] ``` </details>

- `InstanceType<T>` – Obtain the instance type of a constructor function type. <details>

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<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`
    ```
    </details>

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

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<Animal, 'images' | 'paragraphs'>;

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

You can find some examples in the TypeScript docs.

## Maintainers

- Sindre Sorhus
- Jarek Radosz
- Dimitri Benin

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