Skip to content

Instantly share code, notes, and snippets.

@ivanbtrujillo
Last active June 17, 2020 09:40
Show Gist options
  • Save ivanbtrujillo/a5c4789f17d37235ae5dde238b25e6ab to your computer and use it in GitHub Desktop.
Save ivanbtrujillo/a5c4789f17d37235ae5dde238b25e6ab to your computer and use it in GitHub Desktop.
Avoid mutations using Readonly in Typescript
interface User {
id: number;
name: string;
}
// Objects
We are going to change the name of the user. We will have three functions:
- changeName1 : mutates the object. Bad practice because mutations are a source of bugs hard to find.
- changeName2 :give us an error when try to mutate thanks to Readonly
- changeName3 : changes the name returning a new object, avoiding mutation
const user: User = { id: 1, name: 'Julio' };
// 😭 Mutates the object
const changeName1 = (user: User[], name: string) => {
user.name = name;
return user;
};
changeName1(user, 'Ivan');
// 💡 Readonly prevents the mutation
const changeName2 = (user: Readonly<User>, name: string) => {
user.name = name; // Cannot assign to 'name' because it is a read-only property
return user;
};
changeName2(user, 'Ivan');
// 🤩 This is the correct way
const changeName3 = (user: Readonly<User>, name: string) => ({ ...user, name });
changeName3(user, 'Ivan');
// Arrays
We are going to add a new element to the array. We will have three functions:
- addUser1 : mutates the array. Bad practice because mutations are a source of bugs hard to find.
- addUser2 : give us an error when try to add a new user, thanks to ReadonlyArray
- addUser3 : adds the new user, avoiding mutation
const users: User[] = [{ id: 1, name: 'Julio' }];
const userToAdd: User = {
id: 2,
name: 'Iván',
};
// 😭 Mutates the array
const addUser1 = (users: User, user: User) => users.push(user);
addUser1(users, userToAdd);
// 💡 ReadonlyArray prevents the mutation
const addUser2 = (users: ReadonlyArray<User>, user: User) => users.push(user); // Property 'push' does not exist on type 'readonly User[]'
addUser2(users, userToAdd);
// 🤩 This is the correct way
const addUser3 = (users: ReadonlyArray<User>, user: User) => [...users, ...[user]];
addUser3(users, userToAdd);
INFO:
ℹ️ We can use Readonly<User[]> instead of ReadonlyArray<User>:
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#a-new-syntax-for-readonlyarray
ℹ️ We can enable a eslint rule for it:
https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-readonly.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment