Utility Types Collection for TypeScript providing comprehensive type-level utilities for static type manipulation.
—
Flow-style utilities provide TypeScript equivalents of Flow.js utility types, enabling easy migration from Flow to TypeScript and maintaining compatibility with Flow-based codebases.
import {
$Keys, $Values, $ReadOnly, $Diff, $PropertyType, $ElementType,
$Call, $Shape, $NonMaybeType, Class, mixed
} from 'utility-types';Get the union type of all keys in an object type.
type $Keys<T extends object> = keyof T;Usage:
interface User {
id: number;
name: string;
email: string;
}
type UserKeys = $Keys<User>;
// Result: "id" | "name" | "email"
// Use with conditional types
type StringKeys<T> = {
[K in $Keys<T>]: T[K] extends string ? K : never;
}[keyof T];
type UserStringKeys = StringKeys<User>;
// Result: "name" | "email"Get the union type of all values in an object type.
type $Values<T extends object> = T[keyof T];Usage:
interface StatusCodes {
OK: 200;
NOT_FOUND: 404;
SERVER_ERROR: 500;
}
type StatusCode = $Values<StatusCodes>;
// Result: 200 | 404 | 500
interface User {
id: number;
name: string;
active: boolean;
}
type UserValueTypes = $Values<User>;
// Result: number | string | booleanGet the type of a specific property in an object.
type $PropertyType<T extends object, K extends keyof T> = T[K];Usage:
interface User {
id: number;
profile: {
name: string;
avatar: string;
};
}
type UserId = $PropertyType<User, 'id'>;
// Result: number
type UserProfile = $PropertyType<User, 'profile'>;
// Result: { name: string; avatar: string; }
// Useful for extracting nested types
type ProfileName = $PropertyType<UserProfile, 'name'>;
// Result: stringGet the type of elements at a given index in an array, tuple, or object.
type $ElementType<T extends { [P in K & any]: any }, K extends keyof T | number> = T[K];Usage:
// With arrays
type StringArray = string[];
type ArrayElement = $ElementType<StringArray, number>;
// Result: string
// With tuples
type UserTuple = [number, string, boolean];
type FirstElement = $ElementType<UserTuple, 0>;
// Result: number
type SecondElement = $ElementType<UserTuple, 1>;
// Result: string
// With objects (same as $PropertyType)
interface Config {
timeout: number;
retries: number;
}
type TimeoutType = $ElementType<Config, 'timeout'>;
// Result: numberCreate a deeply readonly version of an object type.
type $ReadOnly<T extends object> = DeepReadonly<T>;Usage:
interface Settings {
theme: {
mode: 'light' | 'dark';
colors: string[];
};
user: {
name: string;
preferences: { [key: string]: any };
};
}
type ReadonlySettings = $ReadOnly<Settings>;
// Result: All properties and nested properties become readonly
// {
// readonly theme: {
// readonly mode: 'light' | 'dark';
// readonly colors: readonly string[];
// };
// readonly user: {
// readonly name: string;
// readonly preferences: { readonly [key: string]: any };
// };
// }
// Usage in function parameters
function processSettings(settings: $ReadOnly<Settings>) {
// settings.theme.mode = 'dark'; // Error: Cannot assign to readonly property
console.log(settings.theme.mode); // OK: reading is allowed
}Get the set difference of two object types (properties in T but not in U).
type $Diff<T extends U, U extends object> = Pick<T, SetComplement<keyof T, keyof U>>;Usage:
interface AllProps {
name: string;
age: number;
email: string;
password: string;
}
interface PublicProps {
name: string;
age: number;
email: string;
}
type PrivateProps = $Diff<AllProps, PublicProps>;
// Result: { password: string; }
// Common pattern: removing default props
interface ComponentProps {
title: string;
color: string;
size: 'small' | 'medium' | 'large';
onClick: () => void;
}
interface DefaultProps {
color: string;
size: 'small' | 'medium' | 'large';
}
type RequiredProps = $Diff<ComponentProps, DefaultProps>;
// Result: { title: string; onClick: () => void; }Make all properties in an object type optional (equivalent to Partial).
type $Shape<T extends object> = Partial<T>;Usage:
interface User {
id: number;
name: string;
email: string;
}
type PartialUser = $Shape<User>;
// Result: { id?: number; name?: string; email?: string; }
// Useful for update operations
function updateUser(id: number, updates: $Shape<User>) {
// Can pass any subset of User properties
}
updateUser(1, { name: 'Alice' }); // Valid
updateUser(2, { email: 'bob@example.com', name: 'Bob' }); // Valid
updateUser(3, {}); // ValidRemove null and undefined from a type.
type $NonMaybeType<T> = NonNullable<T>;Usage:
type MaybeString = string | null | undefined;
type DefiniteString = $NonMaybeType<MaybeString>;
// Result: string
type MaybeUser = { name: string; age: number } | null | undefined;
type DefiniteUser = $NonMaybeType<MaybeUser>;
// Result: { name: string; age: number }
// Useful in type guards
function assertNonMaybe<T>(value: T): asserts value is $NonMaybeType<T> {
if (value == null) {
throw new Error('Value is null or undefined');
}
}
declare const maybeValue: string | null;
assertNonMaybe(maybeValue);
// maybeValue is now typed as stringExtract the return type from a function type.
type $Call<Fn extends (...args: any[]) => any> = Fn extends (arg: any) => infer RT ? RT : never;Usage:
function getUserData(id: number): { name: string; email: string } {
return { name: 'User', email: 'user@example.com' };
}
type UserData = $Call<typeof getUserData>;
// Result: { name: string; email: string }
// With generic functions
function createArray<T>(item: T, count: number): T[] {
return Array(count).fill(item);
}
type StringArrayCreator = typeof createArray<string>;
type StringArrayResult = $Call<StringArrayCreator>;
// Result: string[]
// Useful for extracting promise types
async function fetchUser(id: number): Promise<User> {
// ... implementation
}
type FetchUserResult = $Call<typeof fetchUser>;
// Result: Promise<User>Represent a constructor type for a given instance type.
type Class<T> = new (...args: any[]) => T;Usage:
class User {
constructor(public name: string) {}
}
type UserConstructor = Class<User>;
// Result: new (...args: any[]) => User
// Use in factory functions
function createInstance<T>(ctor: Class<T>, ...args: any[]): T {
return new ctor(...args);
}
const user = createInstance(User, 'Alice');
// user is typed as User
// With generics
class Repository<T> {
constructor(private items: T[] = []) {}
add(item: T): void {
this.items.push(item);
}
}
type StringRepository = Repository<string>;
type StringRepositoryConstructor = Class<StringRepository>;Equivalent to TypeScript's unknown type for Flow compatibility.
type mixed = unknown;Usage:
// When migrating from Flow
function processValue(value: mixed): string {
// Must use type guards to narrow the type
if (typeof value === 'string') {
return value.toUpperCase();
}
if (typeof value === 'number') {
return value.toString();
}
return 'unknown';
}
// Prefer unknown in new TypeScript code
function processValueTS(value: unknown): string {
// Same implementation as above
}// Flow code:
// type UserKeys = $Keys<User>;
// type UserValues = $Values<User>;
// type ReadonlyUser = $ReadOnly<User>;
// TypeScript with utility-types:
import { $Keys, $Values, $ReadOnly } from 'utility-types';
type UserKeys = $Keys<User>;
type UserValues = $Values<User>;
type ReadonlyUser = $ReadOnly<User>;
// Gradually migrate to native TypeScript equivalents:
type UserKeysNative = keyof User;
type UserValuesNative = User[keyof User];
type ReadonlyUserNative = DeepReadonly<User>;Install with Tessl CLI
npx tessl i tessl/npm-utility-types