@kakasoo/deep-strict-types
v2.0.11
Published
typescript utility types including deep-strict-omit and pick type
Maintainers
Readme
@kakasoo/deep-strict-types
Type-safe Pick, Omit, and key extraction for deeply nested TypeScript objects and arrays.
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 → recompileThe 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-typesQuick 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
