toothscript
TypeScript icon, indicating that this package has built-in type declarations

0.1.1 • Public • Published

toothscript-shaped

🦷 ToothScript

Welcome to the 🦷 ToothScript Types package! This package provides a curated collection of modular and reusable utility types designed to enhance your TypeScript experience without cluttering the global type namespace. Each utility type is crafted with flexibility and modularity in mind, avoiding conflicts with existing TypeScript behavior while offering precise, documented solutions for real-world use cases.

📜 Table of Contents

🌟 Introduction

This package was inspired by the need for better flexibility and extensibility when working with utility types. While TypeScript offers some built-in types like Omit and Pick, its team has decided not to add new utility types globally, citing potential conflicts and varying user preferences.

Instead, this package embraces user-defined utility types to:

  • Avoid conflicts with TypeScript’s standard library.
  • Provide strict, customizable, and modular definitions.
  • Adapt to project-specific needs with ease.

📦 Installation

You can install the package via npm or pnpm:

npm install toothscript
pnpm install toothscript

🛠️ Utility Types Overview

Key Type Modifications

Assert

Ensures specified keys in a type are non-nullable and non-undefined. Useful for strict type validations.

type Assert<T, K extends keyof T> = Omit<T, K> & {
  [P in K]-?: Exclude<T[P], null | undefined>;
};
  • Example:
interface User {
  name?: string;
  email?: string;
  age: number | null;
}

type StrictUser = Assert<User, 'name' | 'email'>;
// { name: string; email: string; age: number | null; }

StrictOmit

Ensures omitted keys exist in the original type.

type StrictOmit<T, K extends keyof T> = {
  [P in Exclude<keyof T, K>]: T[P];
};
  • Example:
interface User {
  name: string;
  email: string;
  age: number;
}

type UserWithoutAge = StrictOmit<User, 'xage'>;  // Error: 'xage' does not exist in User

NullableKeys

Allows a subset of keys in a type to be nullable.

type NullableKeys<T, K extends keyof T = keyof T> = Omit<T, K> & {
  [P in K]: T[P] | null;
};
  • Example:
type User = {
  name: string;
  email: string;
  image: string;
  age: number;
};

type PartialUser = NullableKeys<User, 'image' | 'age'>;
// { name: string; email: string; image: string | null; age: number | null; }

Type Composition and Transformation

This section includes utility types that help compose and transform types.

DeepPartial

Recursively makes all properties of a type optional.

type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
  • Example:
interface Complex {
  user: {
    name: string;
    address: {
      street: string;
      city: string;
    };
  };
}

type PartialComplex = DeepPartial<Complex>;
// { user?: { name?: string; address?: { street?: string; city?: string; }; }; }

Negate & Nominal

Negates a type or creates a nominal type.

Negate

Negates a type. excluding the specified type. either by type or by key.

export type ExcludeKeys<T, K extends keyof T> = Omit<T, K>;
export type ExcludeType<T, U> = T extends U ? never : T;
  • Example:
type User = {
  name: string;
  email: string;
  age: number;
};

type UserWithoutAge = ExcludeKeys<User, 'age'>;
// { name: string; email: string; }

type UserWithoutString = ExcludeType<User, string>;
// { age: number; }

Nominal

Creates a nominal type by adding a unique tag to the type. to avoid type compatibility. useful for creating unique types. as a signature type.

export type Nominal<Type, Tag extends string> = Type & { readonly __tag: Tag };
  • Example:
type UserId = Nominal<number, 'UserId'>;
type PostId = Nominal<number, 'PostId'>;

const userId: UserId = 1;
const postId: PostId = 1;

if (userId === postId) {
  // Error: Type 'PostId' is not assignable to type 'UserId'
}

🤔 Why Not Global Utility Types?

The TypeScript team has adopted a No New Utility Types policy for the standard library. The reasons include:

  • Conflicts in Naming: New types often overlap with existing or user-defined types, causing confusion or compatibility issues.
  • Semantics Disputes: Definitions for types like Nullable<T> can vary significantly between users.
  • Breaking Changes: Changing or removing a globally available type can cause significant disruptions in existing projects.

This package avoids these issues by:

  • Offering modular utility types that live only in your project’s namespace.
  • Allowing you to tailor types for your specific needs without relying on TypeScript’s global library.

Key Principles:

  • No global pollution.
  • User-focused modularity.
  • Flexibility for both strict and loose typing requirements.

🛡️ Contributing

We welcome contributions! Whether you find a bug, have a feature request, or want to add new types, feel free to contribute.

  • Fork the repository.
  • Create a new branch for your feature or bug fix.
  • Submit a pull request with a detailed explanation.

📄 License

This project is licensed under the MIT License. You are free to use, modify, and distribute this package as long as the license terms are respected.

💬 Feedback

If you have any suggestions or feedback, feel free to open an issue or contact us directly.


By using this package, you retain full control over type design while adhering to TypeScript’s recommended practices. 🎉

Package Sidebar

Install

npm i toothscript

Weekly Downloads

2

Version

0.1.1

License

MIT

Unpacked Size

21.6 kB

Total Files

23

Last publish

Collaborators

  • vvhybe