https://github.com/cmatosbc/tyrany
Tyrannic and repressive Typescript custom utility types.
https://github.com/cmatosbc/tyrany
Last synced: about 2 months ago
JSON representation
Tyrannic and repressive Typescript custom utility types.
- Host: GitHub
- URL: https://github.com/cmatosbc/tyrany
- Owner: cmatosbc
- License: mit
- Created: 2024-12-17T01:30:26.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2024-12-17T02:27:42.000Z (10 months ago)
- Last Synced: 2024-12-17T02:46:20.930Z (10 months ago)
- Language: TypeScript
- Size: 47.9 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Tyrany
[](https://github.com/cmatosbc/tyrany/actions/workflows/node.js.yml)
A comprehensive collection of TypeScript utility types designed to enhance your type-safe development experience. A despotic control over your code behavior, crushing any resistance or mischief from regular JS implementations.
## Installation
```bash
npm install tyrany
# or
yarn add tyrany
# or
pnpm add tyrany
```## Utility Types
### DeepPartial
Makes all properties in a type optional recursively, including nested objects and arrays.```typescript
interface Config {
server: {
port: number;
host: string;
ssl: {
enabled: boolean;
cert: string;
};
};
database: {
url: string;
timeout: number;
};
}// Partial configuration where any property can be omitted
type PartialConfig = DeepPartial;const config: PartialConfig = {
server: {
port: 3000,
// host and ssl can be omitted
},
// database can be omitted
};
```### DeepReadonly
Makes all properties in a type readonly recursively, including nested objects and arrays.```typescript
interface User {
id: number;
name: string;
settings: {
theme: string;
notifications: boolean;
};
posts: Array<{
id: number;
title: string;
}>;
}// All properties become readonly, including nested objects
type ReadonlyUser = DeepReadonly;const user: ReadonlyUser = {
id: 1,
name: "John",
settings: {
theme: "dark",
notifications: true
},
posts: [{ id: 1, title: "Hello" }]
};// TypeScript Error: Cannot modify readonly property
user.settings.theme = "light"; // Error
user.posts[0].title = "Updated"; // Error
```### Exact
Ensures that an object type only allows the exact properties defined, preventing excess properties.```typescript
interface UserInput {
name: string;
age: number;
}type ExactUserInput = Exact;
// TypeScript Error: Object literal may only specify known properties
const input: ExactUserInput = {
name: "John",
age: 30,
extra: true // Error: excess property
};
```### ExtractArrayType
Extracts the type of elements from an array type.```typescript
type StringArray = string[];
type NumberArray = Array;
type UserArray = Array<{ id: number; name: string }>;type String = ExtractArrayType; // string
type Number = ExtractArrayType; // number
type User = ExtractArrayType; // { id: number; name: string }// Practical example with mapped types
function transformArray(array: T[], transform: (item: ExtractArrayType) => string): string[] {
return array.map(transform);
}
```### Mutable
Removes readonly modifiers from all properties in a type.```typescript
interface ReadonlyUser {
readonly id: number;
readonly name: string;
readonly settings: readonly {
readonly theme: string;
readonly notifications: boolean;
};
}type MutableUser = Mutable;
const user: MutableUser = {
id: 1,
name: "John",
settings: {
theme: "dark",
notifications: true
}
};// Now properties can be modified
user.id = 2;
user.settings.theme = "light";
```### NestedOmit
Removes a property deeply from an object type and its nested objects.```typescript
interface ApiResponse {
id: string;
data: {
id: string;
user: {
id: string;
name: string;
};
metadata: {
id: string;
timestamp: number;
};
};
}// Removes all 'id' properties at any level
type CleanResponse = NestedOmit;// Result:
// {
// data: {
// user: {
// name: string;
// };
// metadata: {
// timestamp: number;
// };
// };
// }
```### NonNullable
Removes null and undefined from object properties.```typescript
interface FormData {
name: string | null;
email: string | undefined;
age: number | null;
bio?: string;
}type RequiredFormData = NonNullable;
// Result:
// {
// name: string;
// email: string;
// age: number;
// bio: string;
// }
```### Nullable
Makes all properties in a type nullable (null | undefined).```typescript
interface User {
id: number;
name: string;
email: string;
}type NullableUser = Nullable;
// Useful for partial updates
const userUpdate: NullableUser = {
id: 1,
name: null, // Will clear the name
email: undefined // Will not update the email
};
```### Optional
Makes all properties in a type optional.```typescript
interface Product {
id: number;
name: string;
price: number;
description: string;
category: string;
}type ProductUpdate = Optional;
// All fields are optional
const update: ProductUpdate = {
price: 29.99,
description: "Updated description"
// Other fields can be omitted
};
```### PartialKeys
Makes specific keys of an object type optional while keeping others required.```typescript
interface Article {
id: number;
title: string;
content: string;
author: string;
tags: string[];
}// Make only 'tags' and 'author' optional
type DraftArticle = PartialKeys;const draft: DraftArticle = {
id: 1,
title: "TypeScript Tips",
content: "...",
// tags and author are optional
};
```### PathKeys
Gets all possible dot-notation paths in an object type. Useful for type-safe access to nested object properties.```typescript
interface User {
name: string;
profile: {
age: number;
address: {
street: string;
city: string;
country: {
code: string;
name: string;
}
}
}
}type Paths = PathKeys;
/* Result:
| 'name'
| 'profile'
| 'profile.age'
| 'profile.address'
| 'profile.address.street'
| 'profile.address.city'
| 'profile.address.country'
| 'profile.address.country.code'
| 'profile.address.country.name'
*/// Can be used for type-safe object access utilities
function get>(obj: T, path: P): any {
return path.split('.').reduce((acc, part) => acc[part], obj);
}
```### PickByType
Constructs a new type by picking properties from type `T` whose values are assignable to type `V`.```typescript
interface User {
id: number;
name: string;
isAdmin: boolean;
meta: {
lastLogin: Date;
};
}type StringProperties = PickByType;
// Result: { name: string }type NumberProperties = PickByType;
// Result: { id: number }
```### PickByValue
Similar to PickByType but with more precise type matching, picks properties from type `T` whose values exactly match type `V`.```typescript
interface Config {
port: number;
host: string;
debug: boolean;
timeout: number;
version: string;
}type StringSettings = PickByValue;
// Result: { host: string; version: string }type NumberSettings = PickByValue;
// Result: { port: number; timeout: number }
```### PromiseType
Extracts the type that a Promise resolves to.```typescript
async function fetchUser() {
return { id: 1, name: "John" };
}type FetchUserPromise = ReturnType;
type User = PromiseType;// Useful for API response handling
async function processUser(promise: Promise) {
const user = await promise;
const typedUser = user as PromiseType;
// typedUser is now properly typed
}
```### RequireAtLeastOne
Makes all properties optional but requires at least one property to be present.```typescript
interface SearchCriteria {
name: string;
email: string;
phone: string;
id: number;
}type SearchQuery = RequireAtLeastOne;
// Valid queries
const byName: SearchQuery = { name: "John" };
const byEmailAndPhone: SearchQuery = { email: "john@example.com", phone: "123456" };// TypeScript Error: At least one property must be present
const empty: SearchQuery = {}; // Error
```### Try
Represents a value that can either be a successful result of type `T` or an error of type `E`. Useful for type-safe error handling.```typescript
async function fetchData(): Promise> {
try {
const user = await db.getUser(1);
return { success: true, value: user };
} catch (error) {
return { success: false, error: error as Error };
}
}const result = await fetchData();
if (result.success) {
console.log(result.value.name); // Type-safe access to user properties
} else {
console.error(result.error.message); // Type-safe access to error properties
}
```### UnionToArray
Converts a union type into an array type, useful for working with union types in a more familiar array format.```typescript
type Status = 'pending' | 'active' | 'completed';
type StatusArray = UnionToArray;
// Result: ('pending')[] | ('active')[] | ('completed')[]type Numbers = 1 | 2 | 3;
type NumberArray = UnionToArray;
// Result: (1)[] | (2)[] | (3)[]// Useful for type-safe array operations
const statuses: StatusArray = ['active'];
const numbers: NumberArray = [1, 1, 1];
```### UnionToIntersection
Converts a union type to an intersection type.```typescript
type User = { id: number; name: string };
type Timestamps = { createdAt: Date; updatedAt: Date };
type Metadata = { version: number; isActive: boolean };type UserUnion = User | Timestamps | Metadata;
type FullUser = UnionToIntersection;// Result:
// {
// id: number;
// name: string;
// createdAt: Date;
// updatedAt: Date;
// version: number;
// isActive: boolean;
// }
```### AsyncReturnType
Extracts the return type of an async function, removing the Promise wrapper.```typescript
async function fetchUser() {
return {
id: 1,
name: 'John',
roles: ['admin']
};
}type User = AsyncReturnType;
// Result: { id: number; name: string; roles: string[]; }async function getData(): Promise {
return 42;
}type Data = AsyncReturnType;
// Result: string | number
```### IntersectKeys
Extracts the common keys between two types.```typescript
interface User {
id: number;
name: string;
email: string;
}interface Employee {
id: string;
name: number;
department: string;
}// Get common keys between User and Employee
type CommonKeys = IntersectKeys;
// Result: 'id' | 'name'
```### DeepFreeze
Makes all properties in a type deeply readonly, including nested objects and arrays. This is similar to DeepReadonly but specifically designed for creating immutable data structures.```typescript
interface User {
name: string;
settings: {
theme: string;
notifications: {
email: boolean;
push: boolean;
};
};
tags: string[];
}// Create an immutable user type
type FrozenUser = DeepFreeze;const user: FrozenUser = {
name: 'John',
settings: {
theme: 'dark',
notifications: {
email: true,
push: false,
},
},
tags: ['admin', 'user'],
};// These will cause TypeScript errors:
user.name = 'Jane'; // Error
user.settings.theme = 'light'; // Error
user.tags.push('guest'); // Error
```### Diff
Computes the difference between two types `T` and `U`, excluding properties of type `U` from type `T`.```typescript
// Given types
interface A {
x: number;
y: string;
}interface B {
y: string;
}// Resulting type will be { x: number; }
type Result = Diff;
```## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
MIT License - see the [LICENSE](LICENSE) file for details.