Skip to content

Instantly share code, notes, and snippets.

@AleksejDix
Created March 17, 2025 12:33
Show Gist options
  • Select an option

  • Save AleksejDix/ec47da9cedbb010b37634699446632b5 to your computer and use it in GitHub Desktop.

Select an option

Save AleksejDix/ec47da9cedbb010b37634699446632b5 to your computer and use it in GitHub Desktop.
# TypeScript Style Guide (No Interfaces, Classes, or Enums)
## 1. General Principles
βœ… Prefer **type aliases** over `interface`.
βœ… Use **functional programming** principles.
βœ… Avoid **OOP constructs** like `class`, `interface`, and `enum`.
βœ… Prefer **tuples, records, and discriminated unions**.
βœ… Use `const` and **immutability** wherever possible.
---
## 2. File Naming & Conventions
βœ… Use **PascalCase** for components and types.
βœ… Use **camelCase** for functions, variables, and hooks.
βœ… Use **SCREAMING_SNAKE_CASE** for constants.
βœ… Keep **index.ts** for module re-exports.
βœ… Group related files in folders.
### πŸ“‚ **Recommended Folder Structure**
```
/src
/components
/Button
index.ts # Exports Button for cleaner imports
Button.ts # Main component logic
Button.styles.ts # Styles (if using styled-components or similar)
Button.test.ts # Unit tests
Button.stories.ts # Storybook stories
/hooks
useAuth.ts # Custom hooks (camelCase)
useTheme.ts
/utils
formatDate.ts # Utility functions (camelCase)
fetchData.ts
/constants
API_ENDPOINTS.ts # Constants (SCREAMING_SNAKE_CASE)
COLORS.ts
/types
userTypes.ts # Shared type definitions (PascalCase for types)
```
### βœ… **Example Import Structure**
```ts
import { Button } from "@/components/Button";
import { useAuth } from "@/hooks/useAuth";
import { formatDate } from "@/utils/formatDate";
import { API_ENDPOINTS } from "@/constants/API_ENDPOINTS";
```
---
## 3. Type Definitions
### ❌ **Avoid Interfaces**
βœ… **Use `type` instead**
```ts
// ❌ Bad: Using interfaces
interface User {
id: number;
name: string;
}
// βœ… Good: Using type alias
type User = {
id: number;
name: string;
};
```
---
## 4. No Classes
### ❌ **Avoid Classes**
βœ… **Use functions and object literals**
```ts
// ❌ Bad: Using a class
class User {
constructor(public id: number, public name: string) {}
}
// βœ… Good: Use a factory function
const createUser = (id: number, name: string) => ({ id, name });
const user = createUser(1, "Alice");
```
---
## 5. No Enums
### ❌ **Avoid Enums**
βœ… **Use `const` objects or union types**
```ts
// ❌ Bad: Using enums
enum Status {
Success,
Error,
Loading,
}
// βœ… Good: Use a union type
type Status = "success" | "error" | "loading";
// βœ… Alternative: Use a const object
const Status = {
Success: "success",
Error: "error",
Loading: "loading",
} as const;
type StatusType = typeof Status[keyof typeof Status];
```
---
## 6. Immutability & Functional Programming
βœ… Prefer **readonly** and **immutable structures**
βœ… Use **functional patterns** instead of mutations
```ts
// ❌ Bad: Mutating objects
const user = { id: 1, name: "Alice" };
user.name = "Bob"; // Avoid mutating
// βœ… Good: Return a new object
const updatedUser = { ...user, name: "Bob" };
```
---
## 7. Use Readonly for Objects & Arrays
```ts
// βœ… Prevent mutation
type User = Readonly<{
id: number;
name: string;
}>;
const users: ReadonlyArray<User> = [
{ id: 1, name: "Alice" },
];
// ❌ This will cause a TypeScript error
users[0].name = "Bob"; // Error: Cannot assign to 'name' because it is a read-only property
```
---
## 8. Use Tuples Instead of Classes
```ts
// ❌ Bad: Using a class for a point
class Point {
constructor(public x: number, public y: number) {}
}
// βœ… Good: Use a tuple
type Point = readonly [number, number];
const point: Point = [10, 20];
```
---
## 9. Prefer Function Composition
βœ… **Avoid methods inside objects**, prefer **functions that take objects as arguments**.
```ts
// ❌ Bad: Using a method
const user = {
name: "Alice",
greet() {
return `Hello, ${this.name}`;
},
};
// βœ… Good: Function-based approach
const greet = (user: { name: string }) => `Hello, ${user.name}`;
```
---
## 10. Use Discriminated Unions Instead of Classes
```ts
// ❌ Bad: Using class inheritance
class Success {
type = "success";
}
class Error {
type = "error";
}
// βœ… Good: Use discriminated union
type Response =
| { type: "success"; data: string }
| { type: "error"; message: string };
const handleResponse = (res: Response) => {
if (res.type === "success") {
console.log(res.data);
} else {
console.log(res.message);
}
};
```
---
## 11. Naming Conventions
βœ… Use `camelCase` for variables and functions
βœ… Use `PascalCase` for type aliases
βœ… Use `SCREAMING_SNAKE_CASE` for constants
```ts
const MAX_USERS = 100; // βœ… Correct
const getUserData = () => {}; // βœ… Correct
type UserProfile = { name: string }; // βœ… Correct
```
---
## Conclusion
This guide enforces a **functional, immutable, and lightweight** TypeScript codebase by eliminating `interface`, `class`, and `enum`. It encourages **type aliases, discriminated unions, and object literals** for better maintainability and readability.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment