Type-safe Pick, Omit, and key extraction for deeply nested TypeScript objects and arrays.
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.
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
}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"'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.
npm install @kakasoo/deep-strict-typesimport { 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[] }[] }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"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 } }[];
};
}
*/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 } }[];
};
}
*/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 }[]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[]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 } }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 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"]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' } }| 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" |
ISC
