$ cnpm install typescript-api-pro
TypeScript API Pro provides a complete set of type utilities organized into the following categories:
A union type representing all possible object property key types in JavaScript.
type PropertyKey = string | number | symbol;
PropertyKey typeconst strKey: PropertyKey = 'name'; // string key
const numKey: PropertyKey = 42; // number key
const symKey: PropertyKey = Symbol(); // symbol key
Creates an object type with keys of type PropertyKey and values of generic type T.
type AnyObject<T = any> = Record<PropertyKey, T>;
T defines the type of object values, defaults to anyPropertyKey type// Object with all string values
const strObject: AnyObject<string> = {
name: 'John',
1: 'One',
[Symbol('key')]: 'Symbol value'
};
// Object with all number values
const numObject: AnyObject<number> = {
count: 42,
1: 123,
[Symbol('key')]: 456
};
Creates a type where certain properties must either exist together or not exist at all.
type RequiredDependency<T, K extends keyof T, D extends keyof T>
= Omit<T, D> & (Partial<{ [P in K | D]: never }> | Required<Pick<T, K | D>>);
T: Base object typeK: Key propertyD: Dependent propertyK exists, dependent property D must also existK is not provided, dependent property D cannot be provided eitherinterface Config {
name: string;
host?: string;
port?: number;
}
// Create a type where host and port must exist together or not at all
type ServerConfig = RequiredDependency<Config, 'host', 'port'>;
// ✅ Valid: both host and port are provided
const config1: ServerConfig = {
name: 'server1',
host: 'localhost',
port: 8080
};
// ✅ Valid: neither host nor port is provided
const config2: ServerConfig = {
name: 'server2'
};
// ❌ Invalid: cannot provide host without port
const config3: ServerConfig = {
name: 'server3',
host: 'localhost' // Error
};
// ❌ Invalid: cannot provide port without host
const config4: ServerConfig = {
name: 'server4',
port: 8080 // Error
};
Creates a mutually exclusive object type where only one property from the base type T can be present.
type MutuallyWithObject<T extends AnyObject> = {
[K in keyof T]: { [P in K]: T[K] } & { [P in Exclude<keyof T, K>]?: never };
}[keyof T];
interface LoginOptions {
username: string;
email: string;
phone: number;
}
// Create a type that only allows one login method at a time
type LoginMethod = MutuallyWithObject<LoginOptions>;
// ✅ Valid: using only username
const login1: LoginMethod = {
username: 'user123'
};
// ✅ Valid: using only email
const login2: LoginMethod = {
email: 'user@example.com'
};
// ✅ Valid: using only phone
const login3: LoginMethod = {
phone: 13812345678
};
// ❌ Invalid: cannot provide multiple properties
const login4: LoginMethod = {
username: 'user123',
email: 'user@example.com' // Error
};
Creates a union type where either property K is absent or property O is absent.
type Mutually<T extends AnyObject, K extends keyof T, O extends keyof T> = Omit<T, K> | Omit<T, O>;
T: Base object typeK: First mutually exclusive propertyO: Second mutually exclusive propertyinterface FormData {
name: string;
age: number;
personalId?: string;
passportNumber?: string;
}
// Create a type where personal ID and passport number are mutually exclusive
type IdentityFormData = Mutually<FormData, 'personalId', 'passportNumber'>;
// ✅ Valid: providing personal ID, no passport number
const data1: IdentityFormData = {
name: 'John',
age: 30,
personalId: '110101199001011234'
};
// ✅ Valid: providing passport number, no personal ID
const data2: IdentityFormData = {
name: 'Jane',
age: 25,
passportNumber: 'G12345678'
};
// ✅ Valid: providing neither
const data3: IdentityFormData = {
name: 'Alex',
age: 40
};
// ❌ Invalid: cannot provide both properties
const data4: IdentityFormData = {
name: 'Sam',
age: 35,
personalId: '110101199001011234',
passportNumber: 'G12345678' // Error
};
Creates a new type that inherits all properties from the base type R but overwrites the type of a specific property K with type T.
type Generic<R extends AnyObject, K extends keyof R, T> = Omit<R, K> & { [P in K]: T };
R: Base object typeK: Property key whose type needs to be overwrittenT: New property typeinterface User {
id: number;
name: string;
roles: string[];
}
// Create a new type that changes the roles property from string[] to a more specific Role[] type
interface Role {
id: number;
name: string;
permissions: string[];
}
type EnhancedUser = Generic<User, 'roles', Role[]>;
// ✅ Valid: roles is now of type Role[]
const user: EnhancedUser = {
id: 1,
name: 'John',
roles: [
{ id: 1, name: 'admin', permissions: ['read', 'write', 'delete'] },
{ id: 2, name: 'editor', permissions: ['read', 'write'] }
]
};
Exclude all properties from type T that have the same key names as those in type U.
type OmitByObject<T, U> = Pick<T, Exclude<keyof T, keyof U>>;
T: The source object typeU: The object type containing keys to be omittedOmit, as it can omit properties based on the structure of an entire object type.interface Person {
name: string;
age: number;
address: string;
phone: string;
}
interface ContactInfo {
address: string;
phone: string;
email: string;
}
// Create a type for personal information only, excluding contact info fields
type PersonalInfoOnly = OmitByObject<Person, ContactInfo>;
// Equivalent to { name: string; age: number; }
const personalInfo: PersonalInfoOnly = {
name: 'Zhang San',
age: 30
// address and phone are omitted because they exist in ContactInfo
};
// Another example: Exclude common metadata fields
interface WithMetadata {
id: string;
createdAt: Date;
updatedAt: Date;
}
interface Product extends WithMetadata {
name: string;
price: number;
description: string;
}
// Get only the business data of a product, excluding metadata
type ProductData = OmitByObject<Product, WithMetadata>;
// Equivalent to { name: string; price: number; description: string; }
const productData: ProductData = {
name: 'Smartphone',
price: 3999,
description: 'The latest smartphone'
// id, createdAt, and updatedAt are omitted
};
A utility type that extracts the element type from an array type.
type ArrayItem<T extends any[]> = T[number];
T: Any array typeT[number] to extract the element type from an array type// Simple array type
type NumberArray = number[];
type NumberItem = ArrayItem<NumberArray>; // number
// Tuple type
type StringNumberTuple = [string, number];
type TupleItem = ArrayItem<StringNumberTuple>; // string | number
// Readonly array
type ReadonlyStringArray = ReadonlyArray<string>;
type ReadonlyItem = ArrayItem<ReadonlyStringArray>; // string
// Generic array
interface User {
id: number;
name: string;
}
type UserArray = User[];
type UserItem = ArrayItem<UserArray>; // User
Extracts a union type of all property values from an object type.
type ValueOf<T> = T[keyof T];
T: Any object typeinterface StatusMap {
success: 200;
notFound: 404;
error: 500;
}
type StatusCode = ValueOf<StatusMap>; // 200 | 404 | 500
Gets a union type of all property keys of an object.
type KeyOf<T> = keyof T;
T: Any object typekeyof operatorinterface User {
id: number;
name: string;
age: number;
}
type UserKeys = KeyOf<User>; // "id" | "name" | "age"
Extracts the key type from a Map type.
type MapKeyOf<T extends Map<any, any>> = T extends Map<infer K, any> ? K : never;
T : Any Map typeinfer keyword to extract the key type from a Map typenever if the input is not a Map type// Basic usage
type StringNumberMap = Map<string, number>;
type Keys = MapKeyOf<StringNumberMap>; // string
// Union key type
type UnionKeyMap = Map<string | number, boolean>;
type UnionKeys = MapKeyOf<UnionKeyMap>; // string | number
// Literal key type
type LiteralMap = Map<'name' | 'age', string>;
type LiteralKeys = MapKeyOf<LiteralMap>; // 'name' | 'age'
Extracts the value type from a Map type.
type MapValueOf<T extends Map<unknown, unknown>> = T extends Map<unknown, infer V> ? V : never;
T: Any Map type// Basic usage
type StringNumberMap = Map<string, number>;
type Values = MapValueOf<StringNumberMap>; // number
// Union value type
type UnionValueMap = Map<string, number | boolean>;
type UnionValues = MapValueOf<UnionValueMap>; // number | boolean
// Object value type
interface User {
id: number;
name: string;
}
type UserMap = Map<string, User>;
type UserValue = MapValueOf<UserMap>; // User
Converts a Map type to an equivalent object type.
type MapToObject<T extends Map<unknown, unknown>> = {
[K in MapKeyOf<T> & PropertyKey]: T extends Map<unknown, infer V> ? V : never;
};
T: Any Map typePropertyKey (string | number | symbol)// String key Map
type StringMap = Map<'name' | 'age', string>;
type StringObject = MapToObject<StringMap>;
// { name: string; age: string; }
// Numeric key Map
type NumberMap = Map<1 | 2 | 3, boolean>;
type NumberObject = MapToObject<NumberMap>;
// { 1: boolean; 2: boolean; 3: boolean; }
// Practical example
const userMap: Map<'id' | 'name', string> = new Map([
['id', '123'],
['name', 'John']
]);
// Converted object type
type UserObject = MapToObject<typeof userMap>;
// { id: string; name: string; }
Converts an object type to an equivalent Map type.
type ObjectToMap<T extends AnyObject> = Map<keyof T, T[keyof T]>;
T: Object type inheriting from AnyObject// Basic object conversion
interface User {
id: number;
name: string;
active: boolean;
}
type UserMap = ObjectToMap<User>;
// Map<'id' | 'name' | 'active', number | string | boolean>
// Configuration object conversion
interface Config {
host: string;
port: number;
ssl: boolean;
}
type ConfigMap = ObjectToMap<Config>;
// Map<'host' | 'port' | 'ssl', string | number | boolean>
Creates a new Map type excluding specified keys.
type OmitMapKey<T extends Map<unknown, unknown>, K extends MapKeyOf<T>>
= T extends Map<infer Keys, infer V> ? Map<Exclude<Keys, K>, V> : never;
T: Object type inheriting from AnyObjectK: Keys to exclude (must exist in T)// Exclude single key
type OriginalMap = Map<'name' | 'age' | 'email', string>;
type WithoutEmail = OmitMapKey<OriginalMap, 'email'>;
// Map<'name' | 'age', string>
// Exclude multiple keys (using union type)
type WithoutNameAndAge = OmitMapKey<OriginalMap, 'name' | 'age'>;
// Map<'email', string>
Creates a new Map type including only specified keys.
export type PickMapKey<T extends Map<unknown, unknown>, K extends MapKeyOf<T>>
= T extends Map<unknown, infer V> ? Map<K, V> : never;
T: Object type inheriting from AnyObjectK: Keys to include (must exist in T)// Select single key
type OriginalMap = Map<'name' | 'age' | 'email', string>;
type OnlyName = PickMapKey<OriginalMap, 'name'>;
// Map<'name', string>
// Select multiple keys
type NameAndAge = PickMapKey<OriginalMap, 'name' | 'age'>;
// Map<'name' | 'age', string>
Extracts the element type from a Set type.
type SetValueOf<T extends ReadonlySet<unknown>> = T extends ReadonlySet<infer V> ? V : never;
T: Any Set typeinfernever if the input is not a Set type// Basic usage
type StringSet = Set<string>;
type StringElement = SetValueOf<StringSet>; // string
// Union type elements
type MixedSet = Set<string | number | boolean>;
type MixedElement = SetValueOf<MixedSet>; // string | number | boolean
// Literal type elements
type LiteralSet = Set<'red' | 'green' | 'blue'>;
type ColorElement = SetValueOf<LiteralSet>; // 'red' | 'green' | 'blue'
// Object type elements
interface User {
id: number;
name: string;
}
type UserSet = Set<User>;
type UserElement = SetValueOf<UserSet>; // User
Creates a new Set type excluding specified value types.
type OmitSetValue<T extends Set<unknown>, V extends SetValueOf<T>>
= T extends Set<infer Values> ? Set<Exclude<Values, V>> : never;
T: Any Set typeV: Values to exclude (must exist in T)// Exclude single value type
type OriginalSet = Set<'apple' | 'banana' | 'orange'>;
type WithoutApple = OmitSetValue<OriginalSet, 'apple'>;
// Set<'banana' | 'orange'>
// Exclude multiple value types
type WithoutFruits = OmitSetValue<OriginalSet, 'apple' | 'banana'>;
// Set<'orange'>
// Numeric example
type NumberSet = Set<1 | 2 | 3 | 4 | 5>;
type WithoutOddNumbers = OmitSetValue<NumberSet, 1 | 3 | 5>;
// Set<2 | 4>
Creates a new Set type including only specified value types.
type PickSetValue<T extends Set<unknown>, V extends SetValueOf<T>> = Set<V>;
T: Any Set typeV: Values to include (must exist in T)// Select value types
type OriginalSet = Set<'red' | 'green' | 'blue' | 'yellow'>;
type PrimaryColors = PickSetValue<OriginalSet, 'red' | 'green' | 'blue'>;
// Set<'red' | 'green' | 'blue'>
// Numeric selection
type NumberSet = Set<1 | 2 | 3 | 4 | 5>;
type EvenNumbers = PickSetValue<NumberSet, 2 | 4>;
// Set<2 | 4>
Converts an array type to an equivalent Set type.
type ArrayToSet<T extends readonly unknown[]> = Set<T[number]>;
T[number] to extract element types// Basic array conversion
type StringArray = string[];
type StringSet = ArrayToSet<StringArray>; // Set<string>
// Tuple conversion
type ColorTuple = ['red', 'green', 'blue', 'red'];
type ColorSet = ArrayToSet<ColorTuple>; // Set<'red' | 'green' | 'blue'>
// Union type array
type MixedArray = (string | number)[];
type MixedSet = ArrayToSet<MixedArray>; // Set<string | number>
// Practical example
const fruits = ['apple', 'banana', 'apple', 'orange'] as const;
type FruitSet = ArrayToSet<typeof fruits>;
// Set<'apple' | 'banana' | 'orange'>
Converts a Set type to an equivalent array type.
type SetToArray<T extends ReadonlySet<unknown>> = SetValueOf<T>[];
T: Any array type// Basic Set conversion
type StringSet = Set<string>;
type StringArray = SetToArray<StringSet>; // string[]
// Literal Set conversion
type ColorSet = Set<'red' | 'green' | 'blue'>;
type ColorArray = SetToArray<ColorSet>; // ('red' | 'green' | 'blue')[]
// Object Set conversion
interface User {
id: number;
name: string;
}
type UserSet = Set<User>;
type UserArray = SetToArray<UserSet>; // User[]
// Practical example
function convertSetToArray<T extends Set<any>>(set: T): SetToArray<T> {
return Array.from(set) as SetToArray<T>;
}
Converts camelCase strings to snake_case format.
type Camel2SnakeCase<T extends string, U extends boolean = true> = /* ... */
T: The camelCase string to convertU: Whether to use uppercase (default: true)// Convert to UPPER_SNAKE_CASE (default)
type Result1 = Camel2SnakeCase<'userName'>; // 'USER_NAME'
type Result2 = Camel2SnakeCase<'userId'>; // 'USER_ID'
type Result3 = Camel2SnakeCase<'myVariableName'>; // 'MY_VARIABLE_NAME'
// Convert to lowercase snake_case
type Result4 = Camel2SnakeCase<'userName', false>; // 'user_name'
type Result5 = Camel2SnakeCase<'userId', false>; // 'user_id'
type Result6 = Camel2SnakeCase<'myVariableName', false>; // 'my_variable_name'
// Practical use: API request object conversion
interface UserRequest {
firstName: string;
lastName: string;
emailAddress: string;
}
// Convert to backend API format (UPPER_SNAKE_CASE)
type ApiUserRequest = {
[K in keyof UserRequest as Camel2SnakeCase<K & string>]: UserRequest[K]
};
// Result: { FIRST_NAME: string; LAST_NAME: string; EMAIL_ADDRESS: string; }
// Convert to database field format (lower_snake_case)
type DbUserModel = {
[K in keyof UserRequest as Camel2SnakeCase<K & string, false>]: UserRequest[K]
};
// Result: { first_name: string; last_name: string; email_address: string; }
// Environment variable configuration
interface AppConfig {
databaseUrl: string;
apiKey: string;
maxConnections: number;
}
type EnvVars = {
[K in keyof AppConfig as Camel2SnakeCase<K & string>]: string
};
// Result: { DATABASE_URL: string; API_KEY: string; MAX_CONNECTIONS: string; }
// Type-safe conversion function
function toSnakeCase<T extends Record<string, unknown>>(
obj: T,
uppercase = false
): { [K in keyof T as Camel2SnakeCase<K & string, false>]: T[K] } {
const result: Record<string, unknown> = {};
for (const key in obj) {
const snakeKey = key.replace(/[A-Z]/g, letter =>
`_${uppercase ? letter : letter.toLowerCase()}`);
result[snakeKey] = obj[key];
}
return result as { [K in keyof T as Camel2SnakeCase<K & string, false>]: T[K] };
}
const userData: UserRequest = {
firstName: 'John',
lastName: 'Doe',
emailAddress: 'john@example.com'
};
const dbRecord = toSnakeCase(userData);
// TypeScript ensures type safety
console.log(dbRecord.first_name); // ✅ Valid
// console.log(dbRecord.firstName); // ❌ Error: Property does not exist
Feel free to submit issues or pull requests to help improve Hook-Fetch.
MIT
Copyright 2013 - present © cnpmjs.org | Home |