Replace Elysia with bun.serve for hot reloading and static serving
This commit is contained in:
108
content/2025/09/typescript-tips.md
Normal file
108
content/2025/09/typescript-tips.md
Normal file
@@ -0,0 +1,108 @@
|
||||
---
|
||||
title: 5 TypeScript Tips I Wish I Knew Earlier
|
||||
date: 2025-09-18
|
||||
tags: [TypeScript, JavaScript, Productivity]
|
||||
excerpt: Five practical TypeScript tips that will make your code more type-safe and your development experience smoother. From utility types to const assertions.
|
||||
draft: false
|
||||
---
|
||||
|
||||
# 5 TypeScript Tips I Wish I Knew Earlier
|
||||
|
||||
TypeScript is an amazing tool, but it takes time to learn all its features. Here are five tips that significantly improved my TypeScript development.
|
||||
|
||||
## 1. Use `satisfies` for Type Checking
|
||||
|
||||
The `satisfies` keyword (added in TS 4.9) lets you validate that a value matches a type without widening its type:
|
||||
|
||||
```typescript
|
||||
type RGB = { r: number; g: number; b: number };
|
||||
|
||||
// Before: Type is widened to RGB
|
||||
const color: RGB = { r: 255, g: 0, b: 0 };
|
||||
|
||||
// After: Type is preserved as literal values
|
||||
const color = { r: 255, g: 0, b: 0 } satisfies RGB;
|
||||
```
|
||||
|
||||
This is especially useful when you want both type safety and precise types.
|
||||
|
||||
## 2. Const Assertions
|
||||
|
||||
Adding `as const` to an object or array makes all properties readonly and infers literal types:
|
||||
|
||||
```typescript
|
||||
// Regular array: type is string[]
|
||||
const fruits = ['apple', 'banana'];
|
||||
|
||||
// With const assertion: type is readonly ['apple', 'banana']
|
||||
const fruits = ['apple', 'banana'] as const;
|
||||
```
|
||||
|
||||
This is perfect for configuration objects and enum-like values.
|
||||
|
||||
## 3. Utility Type: `Awaited<T>`
|
||||
|
||||
Need to get the resolved type of a Promise? Use `Awaited`:
|
||||
|
||||
```typescript
|
||||
async function fetchUser() {
|
||||
return { id: 1, name: 'Alice' };
|
||||
}
|
||||
|
||||
// Gets the return type without the Promise wrapper
|
||||
type User = Awaited<ReturnType<typeof fetchUser>>;
|
||||
// User is { id: number; name: string }
|
||||
```
|
||||
|
||||
## 4. Template Literal Types
|
||||
|
||||
Create types based on string patterns:
|
||||
|
||||
```typescript
|
||||
type EventName = 'click' | 'focus' | 'blur';
|
||||
type EventHandler = `on${Capitalize<EventName>}`;
|
||||
// Result: 'onClick' | 'onFocus' | 'onBlur'
|
||||
```
|
||||
|
||||
This is incredibly powerful for creating type-safe APIs.
|
||||
|
||||
## 5. Discriminated Unions
|
||||
|
||||
Use a common property to narrow union types:
|
||||
|
||||
```typescript
|
||||
type Success = { status: 'success'; data: string };
|
||||
type Error = { status: 'error'; error: string };
|
||||
type Result = Success | Error;
|
||||
|
||||
function handle(result: Result) {
|
||||
if (result.status === 'success') {
|
||||
// TypeScript knows this is Success
|
||||
console.log(result.data);
|
||||
} else {
|
||||
// TypeScript knows this is Error
|
||||
console.log(result.error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This pattern eliminates entire classes of runtime errors.
|
||||
|
||||
## Bonus: Non-Null Assertion Operator
|
||||
|
||||
While I generally avoid the `!` operator, it's useful when you know better than TypeScript:
|
||||
|
||||
```typescript
|
||||
// When you're certain the element exists
|
||||
const button = document.getElementById('submit')!;
|
||||
button.click();
|
||||
```
|
||||
|
||||
Use sparingly and only when you're absolutely sure.
|
||||
|
||||
## Wrapping Up
|
||||
|
||||
These tips have made my TypeScript code more robust and easier to maintain. The key is to leverage TypeScript's type system to catch errors at compile time rather than runtime.
|
||||
|
||||
What are your favorite TypeScript features? Let me know!
|
||||
|
||||
Reference in New Issue
Block a user