immutability
Use when modifying objects or arrays. Use when tempted to mutate function parameters. Use when state changes cause unexpected bugs.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Use when modifying objects or arrays. Use when tempted to mutate function parameters. Use when state changes cause unexpected bugs.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Use when writing tests. Use when test structure is unclear. Use when arrange/act/assert phases are mixed.
Use when designing or modifying APIs. Use when adding breaking changes. Use when clients depend on API stability.
Use when implementing authentication. Use when storing passwords. Use when asked to store credentials insecurely.
Use when same data is fetched repeatedly. Use when database queries are slow. Use when implementing caching without invalidation strategy.
Use when tempted to use class inheritance. Use when creating class hierarchies. Use when subclass needs only some parent behavior.
Use when acquiring multiple locks. Use when operations wait for each other. Use when system hangs without crashing.
| name | immutability |
| description | Use when modifying objects or arrays. Use when tempted to mutate function parameters. Use when state changes cause unexpected bugs. |
Never mutate. Always return new objects.
Mutation causes bugs that are hard to track - when objects change unexpectedly, debugging becomes a nightmare. Immutability makes state changes explicit and predictable.
NEVER mutate objects or arrays. ALWAYS return new copies with changes.
No exceptions:
If you're modifying an object directly, STOP:
// ❌ VIOLATION: Direct mutation
function updateUserAddress(user: User, newCity: string): User {
user.address.city = newCity; // Mutates original!
return user;
}
// ❌ VIOLATION: Array mutation
function addItem(cart: CartItem[], item: CartItem): CartItem[] {
cart.push(item); // Mutates original!
return cart;
}
// ❌ VIOLATION: Nested mutation
function updateSettings(config: Config): Config {
config.settings.theme = 'dark'; // Deep mutation!
return config;
}
Problems:
// ✅ CORRECT: Return new object
function updateUserAddress(user: User, newCity: string): User {
return {
...user,
address: {
...user.address,
city: newCity
}
};
}
// ✅ CORRECT: Return new array
function addItem(cart: CartItem[], item: CartItem): CartItem[] {
return [...cart, item];
}
// ✅ CORRECT: Deep immutable update
function updateSettings(config: Config): Config {
return {
...config,
settings: {
...config.settings,
theme: 'dark'
}
};
}
// Usage - originals unchanged
const user = { name: 'Alice', address: { city: 'Boston' } };
const updatedUser = updateUserAddress(user, 'Cambridge');
console.log(user.address.city); // 'Boston' - unchanged!
console.log(updatedUser.address.city); // 'Cambridge' - new object
// Update property
const updated = { ...obj, property: newValue };
// Remove property
const { removed, ...rest } = obj;
// Merge objects
const merged = { ...obj1, ...obj2 };
// Add item
const added = [...arr, newItem];
const prepended = [newItem, ...arr];
// Remove item
const removed = arr.filter(item => item.id !== idToRemove);
// Update item
const updated = arr.map(item =>
item.id === id ? { ...item, ...changes } : item
);
// Sort (creates new array)
const sorted = [...arr].sort((a, b) => a.value - b.value);
// Deep update helper
const updated = {
...state,
users: {
...state.users,
[userId]: {
...state.users[userId],
name: newName
}
}
};
// Or use immer for complex updates
import { produce } from 'immer';
const updated = produce(state, draft => {
draft.users[userId].name = newName; // Looks mutable, but isn't
});
Pressure: "Creating new objects is wasteful"
Response: Modern JS engines optimize this. The bugs from mutation cost more than the memory.
Action: Use immutable patterns. Profile if you suspect performance issues.
Pressure: "Direct mutation is easier to read"
Response: Simple to write, hard to debug. Immutability is simpler in the long run.
Action: Spread operators are not complex. Use them.
Pressure: "I'm only changing one field"
Response: One mutation sets a precedent. Others follow. Bugs multiply.
Action: All updates return new objects. No exceptions.
Pressure: "This object is local, mutation is safe"
Response: Code evolves. Local becomes shared. Build the habit now.
Action: Always immutable, regardless of current usage.
obj.property = value (direct assignment)array.push(), array.pop(), array.splice()array.sort() without spreading firstdelete obj.propertyAll of these mean: Rewrite immutably.
| Mutable (Bad) | Immutable (Good) |
|---|---|
obj.x = y | { ...obj, x: y } |
arr.push(x) | [...arr, x] |
arr.pop() | arr.slice(0, -1) |
arr.splice(i, 1) | arr.filter((_, idx) => idx !== i) |
arr.sort() | [...arr].sort() |
delete obj.x | const { x, ...rest } = obj |
| Excuse | Reality |
|---|---|
| "More efficient" | Bugs cost more than memory. |
| "Simpler" | Simpler to write, harder to debug. |
| "Just one property" | One exception leads to many. |
| "No one else uses it" | Code changes. Be consistent. |
| "Too verbose" | Spread syntax is concise. |
| "React handles it" | React needs new references to detect changes. |
Never mutate. Spread and return new objects.
Every modification returns a new object. Original data stays unchanged. This enables debugging, undo/redo, React change detection, and sanity.