npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

tyrany

v1.2.1

Published

A TypeScript library of utility types

Downloads

106

Readme

Tyrany

A comprehensive collection of TypeScript utility types designed to enhance your type-safe development experience. A despotic control over your code behavior, crushing any resistance or mischief from regular JS implementations.

Installation

npm install tyrany
# or
yarn add tyrany
# or
pnpm add tyrany

Utility Types

DeepPartial

Makes all properties in a type optional recursively, including nested objects and arrays.

interface Config {
  server: {
    port: number;
    host: string;
    ssl: {
      enabled: boolean;
      cert: string;
    };
  };
  database: {
    url: string;
    timeout: number;
  };
}

// Partial configuration where any property can be omitted
type PartialConfig = DeepPartial<Config>;

const config: PartialConfig = {
  server: {
    port: 3000,
    // host and ssl can be omitted
  },
  // database can be omitted
};

DeepReadonly

Makes all properties in a type readonly recursively, including nested objects and arrays.

interface User {
  id: number;
  name: string;
  settings: {
    theme: string;
    notifications: boolean;
  };
  posts: Array<{
    id: number;
    title: string;
  }>;
}

// All properties become readonly, including nested objects
type ReadonlyUser = DeepReadonly<User>;

const user: ReadonlyUser = {
  id: 1,
  name: "John",
  settings: {
    theme: "dark",
    notifications: true
  },
  posts: [{ id: 1, title: "Hello" }]
};

// TypeScript Error: Cannot modify readonly property
user.settings.theme = "light"; // Error
user.posts[0].title = "Updated"; // Error

Exact

Ensures that an object type only allows the exact properties defined, preventing excess properties.

interface UserInput {
  name: string;
  age: number;
}

type ExactUserInput = Exact<UserInput>;

// TypeScript Error: Object literal may only specify known properties
const input: ExactUserInput = {
  name: "John",
  age: 30,
  extra: true // Error: excess property
};

ExtractArrayType

Extracts the type of elements from an array type.

type StringArray = string[];
type NumberArray = Array<number>;
type UserArray = Array<{ id: number; name: string }>;

type String = ExtractArrayType<StringArray>; // string
type Number = ExtractArrayType<NumberArray>; // number
type User = ExtractArrayType<UserArray>; // { id: number; name: string }

// Practical example with mapped types
function transformArray<T>(array: T[], transform: (item: ExtractArrayType<T[]>) => string): string[] {
  return array.map(transform);
}

Mutable

Removes readonly modifiers from all properties in a type.

interface ReadonlyUser {
  readonly id: number;
  readonly name: string;
  readonly settings: readonly {
    readonly theme: string;
    readonly notifications: boolean;
  };
}

type MutableUser = Mutable<ReadonlyUser>;

const user: MutableUser = {
  id: 1,
  name: "John",
  settings: {
    theme: "dark",
    notifications: true
  }
};

// Now properties can be modified
user.id = 2;
user.settings.theme = "light";

NestedOmit<T, K>

Removes a property deeply from an object type and its nested objects.

interface ApiResponse {
  id: string;
  data: {
    id: string;
    user: {
      id: string;
      name: string;
    };
    metadata: {
      id: string;
      timestamp: number;
    };
  };
}

// Removes all 'id' properties at any level
type CleanResponse = NestedOmit<ApiResponse, 'id'>;

// Result:
// {
//   data: {
//     user: {
//       name: string;
//     };
//     metadata: {
//       timestamp: number;
//     };
//   };
// }

NonNullable

Removes null and undefined from object properties.

interface FormData {
  name: string | null;
  email: string | undefined;
  age: number | null;
  bio?: string;
}

type RequiredFormData = NonNullable<FormData>;

// Result:
// {
//   name: string;
//   email: string;
//   age: number;
//   bio: string;
// }

Nullable

Makes all properties in a type nullable (null | undefined).

interface User {
  id: number;
  name: string;
  email: string;
}

type NullableUser = Nullable<User>;

// Useful for partial updates
const userUpdate: NullableUser = {
  id: 1,
  name: null, // Will clear the name
  email: undefined // Will not update the email
};

Optional

Makes all properties in a type optional.

interface Product {
  id: number;
  name: string;
  price: number;
  description: string;
  category: string;
}

type ProductUpdate = Optional<Product>;

// All fields are optional
const update: ProductUpdate = {
  price: 29.99,
  description: "Updated description"
  // Other fields can be omitted
};

PartialKeys<T, K>

Makes specific keys of an object type optional while keeping others required.

interface Article {
  id: number;
  title: string;
  content: string;
  author: string;
  tags: string[];
}

// Make only 'tags' and 'author' optional
type DraftArticle = PartialKeys<Article, 'tags' | 'author'>;

const draft: DraftArticle = {
  id: 1,
  title: "TypeScript Tips",
  content: "...",
  // tags and author are optional
};

PathKeys

Gets all possible dot-notation paths in an object type. Useful for type-safe access to nested object properties.

interface User {
  name: string;
  profile: {
    age: number;
    address: {
      street: string;
      city: string;
      country: {
        code: string;
        name: string;
      }
    }
  }
}

type Paths = PathKeys<User>;
/* Result:
  | 'name'
  | 'profile'
  | 'profile.age'
  | 'profile.address'
  | 'profile.address.street'
  | 'profile.address.city'
  | 'profile.address.country'
  | 'profile.address.country.code'
  | 'profile.address.country.name'
*/

// Can be used for type-safe object access utilities
function get<T, P extends PathKeys<T>>(obj: T, path: P): any {
  return path.split('.').reduce((acc, part) => acc[part], obj);
}

PickByType<T, V>

Constructs a new type by picking properties from type T whose values are assignable to type V.

interface User {
  id: number;
  name: string;
  isAdmin: boolean;
  meta: {
    lastLogin: Date;
  };
}

type StringProperties = PickByType<User, string>;
// Result: { name: string }

type NumberProperties = PickByType<User, number>;
// Result: { id: number }

PickByValue<T, V>

Similar to PickByType but with more precise type matching, picks properties from type T whose values exactly match type V.

interface Config {
  port: number;
  host: string;
  debug: boolean;
  timeout: number;
  version: string;
}

type StringSettings = PickByValue<Config, string>;
// Result: { host: string; version: string }

type NumberSettings = PickByValue<Config, number>;
// Result: { port: number; timeout: number }

PromiseType

Extracts the type that a Promise resolves to.

async function fetchUser() {
  return { id: 1, name: "John" };
}

type FetchUserPromise = ReturnType<typeof fetchUser>;
type User = PromiseType<FetchUserPromise>;

// Useful for API response handling
async function processUser(promise: Promise<unknown>) {
  const user = await promise;
  const typedUser = user as PromiseType<typeof promise>;
  // typedUser is now properly typed
}

RequireAtLeastOne

Makes all properties optional but requires at least one property to be present.

interface SearchCriteria {
  name: string;
  email: string;
  phone: string;
  id: number;
}

type SearchQuery = RequireAtLeastOne<SearchCriteria>;

// Valid queries
const byName: SearchQuery = { name: "John" };
const byEmailAndPhone: SearchQuery = { email: "[email protected]", phone: "123456" };

// TypeScript Error: At least one property must be present
const empty: SearchQuery = {}; // Error

Try<T, E>

Represents a value that can either be a successful result of type T or an error of type E. Useful for type-safe error handling.

async function fetchData(): Promise<Try<User, Error>> {
  try {
    const user = await db.getUser(1);
    return { success: true, value: user };
  } catch (error) {
    return { success: false, error: error as Error };
  }
}

const result = await fetchData();
if (result.success) {
  console.log(result.value.name); // Type-safe access to user properties
} else {
  console.error(result.error.message); // Type-safe access to error properties
}

UnionToArray

Converts a union type into an array type, useful for working with union types in a more familiar array format.

type Status = 'pending' | 'active' | 'completed';
type StatusArray = UnionToArray<Status>;
// Result: ('pending')[] | ('active')[] | ('completed')[]

type Numbers = 1 | 2 | 3;
type NumberArray = UnionToArray<Numbers>;
// Result: (1)[] | (2)[] | (3)[]

// Useful for type-safe array operations
const statuses: StatusArray = ['active'];
const numbers: NumberArray = [1, 1, 1];

UnionToIntersection

Converts a union type to an intersection type.

type User = { id: number; name: string };
type Timestamps = { createdAt: Date; updatedAt: Date };
type Metadata = { version: number; isActive: boolean };

type UserUnion = User | Timestamps | Metadata;
type FullUser = UnionToIntersection<UserUnion>;

// Result:
// {
//   id: number;
//   name: string;
//   createdAt: Date;
//   updatedAt: Date;
//   version: number;
//   isActive: boolean;
// }

AsyncReturnType

Extracts the return type of an async function, removing the Promise wrapper.

async function fetchUser() {
  return {
    id: 1,
    name: 'John',
    roles: ['admin']
  };
}

type User = AsyncReturnType<typeof fetchUser>; 
// Result: { id: number; name: string; roles: string[]; }

async function getData(): Promise<string | number> {
  return 42;
}

type Data = AsyncReturnType<typeof getData>;
// Result: string | number

IntersectKeys<T, U>

Extracts the common keys between two types.

interface User {
  id: number;
  name: string;
  email: string;
}

interface Employee {
  id: string;
  name: number;
  department: string;
}

// Get common keys between User and Employee
type CommonKeys = IntersectKeys<User, Employee>;
// Result: 'id' | 'name'

DeepFreeze

Makes all properties in a type deeply readonly, including nested objects and arrays. This is similar to DeepReadonly but specifically designed for creating immutable data structures.

interface User {
  name: string;
  settings: {
    theme: string;
    notifications: {
      email: boolean;
      push: boolean;
    };
  };
  tags: string[];
}

// Create an immutable user type
type FrozenUser = DeepFreeze<User>;

const user: FrozenUser = {
  name: 'John',
  settings: {
    theme: 'dark',
    notifications: {
      email: true,
      push: false,
    },
  },
  tags: ['admin', 'user'],
};

// These will cause TypeScript errors:
user.name = 'Jane';              // Error
user.settings.theme = 'light';   // Error
user.tags.push('guest');         // Error

Diff<T, U>

Computes the difference between two types T and U, excluding properties of type U from type T.

// Given types
interface A {
  x: number;
  y: string;
}

interface B {
  y: string;
}

// Resulting type will be { x: number; }
type Result = Diff<A, B>;

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see the LICENSE file for details.