From ff48cd20b0599febb74afe1afab4a5d68a948c29 Mon Sep 17 00:00:00 2001 From: Andrei Calinescu Date: Thu, 21 Jul 2022 23:58:43 +0900 Subject: [PATCH] add ts immutable objects or arrays as const --- README.md | 3 ++ .../immutable-objects-or-arrays-as-const.md | 52 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 typescript/immutable-objects-or-arrays-as-const.md diff --git a/README.md b/README.md index a0f937f..d632778 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ This repo is inspired by the [@jbrandchaud/til](https://github.com/jbranchaud/ti - [Office Software](#office-software) - [Scrum](#scrum) - [SVG](#svg) +- [TypeScript](#typescript) - [VS Code](#vs-code) ## Table of Contents @@ -109,6 +110,8 @@ This repo is inspired by the [@jbrandchaud/til](https://github.com/jbranchaud/ti - [SVG Online Dev Tools](svg/svg-online-dev-tools.md) +### TypeScript +- [Immutable objects or arrays with `as const`](typescript/immutable-objects-or-arrays-as-const.md) ### VS Code - [`[Command]` - Copy GitHub permalink to code snippet](vscode/command-copy-github-permalink-to-code-snippet.md) diff --git a/typescript/immutable-objects-or-arrays-as-const.md b/typescript/immutable-objects-or-arrays-as-const.md new file mode 100644 index 0000000..e73299c --- /dev/null +++ b/typescript/immutable-objects-or-arrays-as-const.md @@ -0,0 +1,52 @@ +# Immutable objects or arrays with `as const` + +When JavaScript introduced the word `const` declaration, it was an overdue and welcome change. Finally, variables could be designated as read-only, to prevent accidental mutations. + +Unless those variables are `objects` or `arrays` because... reasons. + +> The value of a constant can't be changed through reassignment (i.e. by using the assignment operator), and it can't be redeclared (i.e. through a variable declaration). However, if a constant is an `object` or `array` its properties or items can be updated or removed. 🤦 ([MDN Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const)) + +This means `const` is quite the misnomer. + +Luckily TypeScript heard our sighs and introduced the [`const assertion`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions) 😎 + +The `const assertion` turns **any** simple variable read-only. + +```js +// JS lets you do this +const arr = ['foo', 'bar'] +arr.push('foobar'); // ['foo', 'bar', 'foobar'] + +const obj = {foo: 'bar'} +obj.foo = 'foo' // {foo: 'foo'} +``` +TypeScript is more civilized. Still, the syntax does look a bit odd and somewhat redundant at first. Seeing `const` at the beginning and end of the declaration seems a bit silly. It's worth it though! + +```ts +const arr = ['foo', 'bar'] as const +arr.push('foobar'); // Property 'push' does not exist on type 'readonly ["foo", "bar"]'. + +const obj = {foo: 'bar'} as const; +obj.foo = 'foo' // Cannot assign to 'foo' because it is a read-only property. +``` + +Yes, JavaScript has [`Object.freeze()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze), but TS' `const assertion` works better and prevents deep mutations as far as I can tell. + +```js +let obj1 = { + internal: {a: 'b'} +}; + +Object.freeze(obj1); +obj1.internal.a = 'aValue'; // internal: {a: 'aValue'} +``` + +```ts +let obj1 = { + internal: {a: 'b'} +} as const; + +obj1.internal.a = 'aValue'; // Cannot assign to 'a' because it is a read-only property. +``` + +Finally, `const` is no longer a misnomer 🎉 \ No newline at end of file