Skip to content

kakasoo/DeepStrictTypes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

171 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

@kakasoo/deep-strict-types

npm version License: ISC TypeScript

Type-safe Pick, Omit, and key extraction for deeply nested TypeScript objects and arrays.

한국어 설명

example

Why in the AI Era?

AI writes more code than ever — and makes more subtle mistakes than ever. This library serves as a compile-time guardrail for AI-generated code.

The Problem

AI coding tools often produce code that looks correct but has subtle type mismatches in deeply nested structures:

// AI-generated code: looks fine, but "prce" is a typo
function getTotal(order: Order) {
  return order.items.map(i => i.prce); // no error with loose types
}

The Solution

With strict deep types as constraints, the TypeScript compiler catches AI mistakes instantly:

import { DeepStrictPick } from '@kakasoo/deep-strict-types';

type OrderSummary = DeepStrictPick<Order, 'items[*].price' | 'customer.name'>;

// Now AI gets a precise error:
// Type '"items[*].prce"' is not assignable to
//   type '"items" | "items[*]" | "items[*].price" | "customer" | "customer.name"'

AI Self-Correction Loop

When used with tsc or tsx in a build loop, AI agents can read the type error, understand exactly what went wrong, and fix it automatically:

AI generates code → tsc compile → type error → AI reads error → AI self-corrects → recompile

The stricter your types, the better the error messages, and the faster AI converges on correct code. In an AI-driven workflow, deep strict types aren't overhead — they're the safety net.

Installation

npm install @kakasoo/deep-strict-types

Quick Start

import { DeepStrictObjectKeys, DeepStrictPick, DeepStrictOmit } from '@kakasoo/deep-strict-types';

type User = {
  id: string;
  profile: {
    name: string;
    age: number;
  };
  posts: {
    title: string;
    tags: string[];
  }[];
};

// Extract all nested key paths
type Keys = DeepStrictObjectKeys<User>;
// "id" | "profile" | "profile.name" | "profile.age" | "posts" | "posts[*].title" | "posts[*].tags"

// Pick only what you need
type NameOnly = DeepStrictPick<User, 'profile.name'>;
// { profile: { name: string } }

// Remove what you don't need
type NoAge = DeepStrictOmit<User, 'profile.age'>;
// { id: string; profile: { name: string }; posts: { title: string; tags: string[] }[] }

Core Types

DeepStrictObjectKeys<T>

Extracts all keys from a nested object as a union of dot-notation string paths. Arrays use [*] notation.

type Example = {
  user: {
    name: string;
    address: { city: string; zip: number };
  };
};

type Keys = DeepStrictObjectKeys<Example>;
// "user" | "user.name" | "user.address" | "user.address.city" | "user.address.zip"
type WithArray = { items: { name: string; price: number }[] };

type Keys = DeepStrictObjectKeys<WithArray>;
// "items" | "items[*].name" | "items[*].price"

DeepStrictPick<T, K>

Creates a new type by selecting only the specified nested keys, preserving the object structure.

type Example = {
  user: {
    id: string;
    profile: { name: string; age: number; email: string };
    posts: { title: string; content: string; meta: { likes: number; shares: number } }[];
  };
};

type Picked = DeepStrictPick<Example, 'user.profile.name' | 'user.posts[*].meta.likes'>;
/*
  {
    user: {
      profile: { name: string };
      posts: { meta: { likes: number } }[];
    };
  }
*/

DeepStrictOmit<T, K>

Creates a new type by removing the specified nested keys.

type Omitted = DeepStrictOmit<Example, 'user.profile.email' | 'user.posts[*].meta.shares'>;
/*
  {
    user: {
      id: string;
      profile: { name: string; age: number };
      posts: { title: string; content: string; meta: { likes: number } }[];
    };
  }
*/

DeepStrictMerge<Target, Source>

Deeply merges two object types. When both types share a key, Target takes precedence.

type A = { user: { id: string; profile: { name: string } } };
type B = { user: { profile: { email: string }; settings: { theme: string } } };

type Merged = DeepStrictMerge<A, B>;
/*
  {
    user: {
      id: string;
      profile: { name: string; email: string };
      settings: { theme: string };
    };
  }
*/

Arrays of objects are also merged element-wise:

type Merged = DeepStrictMerge<{ a: number }[], { b: string }[]>;
// { a: number; b: string }[]

GetType<T, K>

Extracts the type at a specific nested path.

type Data = {
  user: {
    name: string;
    posts: { title: string; tags: string[] }[];
  };
};

type T1 = GetType<Data, 'user.name'>;           // string
type T2 = GetType<Data, 'user.posts'>;           // { title: string; tags: string[] }[]
type T3 = GetType<Data, 'user.posts[*].title'>;  // string
type T4 = GetType<Data, 'user.posts[*].tags'>;   // string[]

DeepDateToString<T>

Recursively converts all Date types to string. Useful for representing serialized/JSON response types.

type Input = {
  createdAt: Date;
  user: { name: string; birthDate: Date };
};

type Output = DeepDateToString<Input>;
// { createdAt: string; user: { name: string; birthDate: string } }

DeepStrictUnbrand<T>

Recursively removes branding (e.g., typia tags like Format<'uuid'>) from types, restoring base primitives.

type Branded = {
  id: string & { __brand: 'uuid' };
  profile: { email: string & { __brand: 'email' } };
};

type Clean = DeepStrictUnbrand<Branded>;
// { id: string; profile: { email: string } }

Runtime Functions

deepStrictObjectKeys(obj)

Runtime counterpart of DeepStrictObjectKeys. Returns an array of all dot-notation key paths.

import { deepStrictObjectKeys } from '@kakasoo/deep-strict-types';

const keys = deepStrictObjectKeys({ a: { b: 1, c: 2 } });
// ["a", "a.b", "a.c"]

deepStrictAssert(obj)(key)

Curried runtime function that extracts a specific nested property, preserving the object structure. Type-safe counterpart of DeepStrictPick.

import { deepStrictAssert } from '@kakasoo/deep-strict-types';

const data = {
  user: { name: 'Alice', age: 30 },
  posts: [{ title: 'Hello', content: 'World' }],
};

const result = deepStrictAssert(data)('user.name');
// { user: { name: 'Alice' } }

Utility Types

Type Description Example
DeepStrictObjectLastKeys<T> Extracts only the leaf-level (deepest) keys "a.b.c" instead of "a" | "a.b" | "a.b.c"
StringToDeepObject<T> Converts a comma-separated dot-notation string to a nested object type StringToDeepObject<"a.b,c"> = { a: { b: any }; c: any }
Equal<X, Y> Type-level equality check (returns true or false) Equal<string, string> = true
ElementOf<T> Extracts the element type from an array ElementOf<string[]> = string
IsAny<T> Checks if a type is any IsAny<any> = true
IsUnion<T> Checks if a type is a union IsUnion<string | number> = true
ValueType Union of all primitive types + Date string | number | boolean | ...
GetMember<T, Prefix> Extracts key segments after a dot-notation prefix Internal helper for DeepStrictOmit
GetElementMember<T, Prefix> Extracts array element sub-keys after a [*] prefix Internal helper for DeepStrictOmit
RemoveAfterDot<T, K> Generates wildcard patterns for descendant keys Internal helper for DeepStrictPick
RemoveArraySymbol<T> Strips [*] suffix from a key string RemoveArraySymbol<"items[*]"> = "items"
RemoveLastProperty<T> Extracts all parent path segments RemoveLastProperty<"a.b.c"> = "a" | "a.b"

License

ISC