<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Today I Learned]]></title><description><![CDATA[Today I Learned]]></description><link>https://chris-seaton.co.uk</link><generator>RSS for Node</generator><lastBuildDate>Sun, 19 Apr 2026 15:56:18 GMT</lastBuildDate><atom:link href="https://chris-seaton.co.uk/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[The Demise of Google Optimise]]></title><description><![CDATA[A few months ago, Google announced that its free A/B testing service would be shut down at the end of September. Obviously, this wasn't the most popular decision, but there wasn't much end users could do other than migrate to another service, such as...]]></description><link>https://chris-seaton.co.uk/the-demise-of-google-optimise</link><guid isPermaLink="true">https://chris-seaton.co.uk/the-demise-of-google-optimise</guid><category><![CDATA[AWS]]></category><category><![CDATA[google optimize]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Sun, 10 Sep 2023 15:53:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/uKlneQRwaxY/upload/3324bba52d0b3ed0778eed9f6eb549b6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A few months ago, Google announced that its <a target="_blank" href="https://optimize.google.com/">free A/B testing service</a> would be shut down at the end of September. Obviously, this wasn't the most popular decision, but there wasn't much end users could do other than migrate to another service, such as <a target="_blank" href="https://www.optimizely.com/">Optimizely</a> or <a target="_blank" href="https://vwo.com/">VWO</a>.</p>
<p>These feature-complete services offer a great deal of functionality but also come with a hefty price tag for its more significant users. So for cost-conscious businesses, you'd have to look further afield.</p>
<p>Enter <a target="_blank" href="https://aws.amazon.com/blogs/aws/cloudwatch-evidently/">AWS CloudWatch Evidently</a>.</p>
<p>For companies with developer resources and already utilising the AWS SDK in their language of choice, this is certainly worth considering if you require only a small subset of features. Like many serverless products, you're billed for the number of API calls you make once you reach a certain threshold. If you choose to store the events or metrics, these incur additional fees too. The free tier is quite generous, and if you set a retention policy on the CloudWatch logs, you aren't likely to be surprised by a huge bill at the end of the month.</p>
<p>If you're looking for a basic redirect test, or perhaps some component-level switching, this might be the service for you.</p>
]]></content:encoded></item><item><title><![CDATA[Streamlining the execution of Python scripts]]></title><description><![CDATA[In recent months, I've been dabbling in a bit of Python. It's easy to get to grips with, and the syntax is clean. Closely following a variety of tutorials, I'd simply write some code in hello-world.py, then execute it like so:
chris@chris-book:~$ pyt...]]></description><link>https://chris-seaton.co.uk/streamlining-the-execution-of-python-scripts</link><guid isPermaLink="true">https://chris-seaton.co.uk/streamlining-the-execution-of-python-scripts</guid><category><![CDATA[Bash]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Tue, 05 Sep 2023 21:47:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/vb-3qEe3rg8/upload/666053b5078fe62bd74ca06af8d5b59e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In recent months, I've been dabbling in a bit of Python. It's easy to get to grips with, and the syntax is clean. Closely following a variety of tutorials, I'd simply write some code in <code>hello-world.py</code>, then execute it like so:</p>
<pre><code class="lang-bash">chris@chris-book:~$ python3 hello-world.py
</code></pre>
<p>This would work, and I thought that's just how you ran the code. Anyway, while starting a new course, I just discovered that you can streamline this process using a <a target="_blank" href="https://en.wikipedia.org/wiki/Shebang_(Unix)">shebang</a>:</p>
<ol>
<li><p>Make the file executable using <code>chmod</code> (make sure you consider which users/groups should be permitted to do this, obviously)</p>
</li>
<li><p>Append <code>#!/bin/python3</code> to the start of the file</p>
<pre><code class="lang-python"> <span class="hljs-comment">#!/bin/python3</span>
 print(<span class="hljs-string">"Hello World"</span>);
</code></pre>
</li>
<li><p>Execute the file</p>
<pre><code class="lang-bash"> chris@chris-book:~$ ./hello-world.py
 Hello World
</code></pre>
</li>
</ol>
<p>Keep in mind that you can do this with other program files too.</p>
]]></content:encoded></item><item><title><![CDATA[The Six Advantages of Cloud Computing]]></title><description><![CDATA[This is a bit less developer-centric than my usual posts, but since I'm currently looking towards taking my AWS Solutions Architect Associate exam later in the year (or early 2024), I wanted to take a refresher in the basics.
Below are the six advant...]]></description><link>https://chris-seaton.co.uk/the-six-advantages-of-cloud-computing</link><guid isPermaLink="true">https://chris-seaton.co.uk/the-six-advantages-of-cloud-computing</guid><category><![CDATA[Cloud Computing]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Mon, 21 Aug 2023 21:04:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/A9_IsUtjHm4/upload/1aac178b56d3569593b83f363f51a2d4.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is a bit less developer-centric than my usual posts, but since I'm currently looking towards taking my AWS Solutions Architect Associate exam later in the year (or early 2024), I wanted to take a refresher in the basics.</p>
<p>Below are the six advantages of cloud computing, courtesy of <a target="_blank" href="https://docs.aws.amazon.com/whitepapers/latest/aws-overview/six-advantages-of-cloud-computing.html">Amazon Web Services</a>:</p>
<ol>
<li><p><strong>Trade CapEx for OpEx</strong> - rather than paying upfront for hardware, you pay for it as its used</p>
</li>
<li><p><strong>Benefit from economies of scale</strong> - cloud providers buy things at a much larger scale, so benefit from cheaper rates</p>
</li>
<li><p><strong>Stop guessing capacity</strong> - spin up what you need, then update the hardware as your requirements change. This is much better than over-provisioning, resulting in expensive, under-utilised equipment.</p>
</li>
<li><p><strong>Increased speed and agility</strong> - the lead time to acquire hardware and other services are minutes away rather than days, weeks and months seen by acquiring the hardware yourself.</p>
</li>
<li><p><strong>Reduced data centre operational costs</strong> - running your own data centres is expensive. The physical building, all of the hardware and utility prices quickly stack up - and that's before staffing expenses. Make it Amazon's problem.</p>
</li>
<li><p><strong>Go global in minutes</strong> - with cloud providers you can deploy to regions all around the world, to be closer to your users and provide the best possible experience.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Wildcard searching in the terminal]]></title><description><![CDATA[While I often reach for * when searching for files in the terminal, I just discovered that the ? symbol represents a single character. Secondly, in a similar manner to regex, you can also specify a subset of characters by placing them in [].
chris@ch...]]></description><link>https://chris-seaton.co.uk/wildcard-searching-in-the-terminal</link><guid isPermaLink="true">https://chris-seaton.co.uk/wildcard-searching-in-the-terminal</guid><category><![CDATA[linux for beginners]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Sun, 20 Aug 2023 18:01:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/webyw4NsFPg/upload/21b04e290079a6bb1d22a8a8c136d727.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While I often reach for <code>*</code> when searching for files in the terminal, I just discovered that the <code>?</code> symbol represents a single character. Secondly, in a similar manner to regex, you can also specify a subset of characters by placing them in <code>[]</code>.</p>
<pre><code class="lang-bash">chris@chris-book:~$ ls sho*.txt
shoe.txt shogun.txt shoot.txt shot.txt

chris@chris-book:~$ ls sho?.txt
shoe.txt shot.txt

chris@chris-book:~$ ls sho[efg].txt
shoe.txt
</code></pre>
<p>So you too can now be more powerful with your search!</p>
]]></content:encoded></item><item><title><![CDATA[Styling checkbox colours]]></title><description><![CDATA[While watching the recent Tailwind Connect recording, I discovered a new utility class named accent-lime-400 . I'd never seen this one, but after some digging, I think it's pretty cool and helps make UIs more consistent with the brand theming.
You ca...]]></description><link>https://chris-seaton.co.uk/styling-checkbox-colours</link><guid isPermaLink="true">https://chris-seaton.co.uk/styling-checkbox-colours</guid><category><![CDATA[CSS]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Tue, 01 Aug 2023 06:49:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/jbtfM0XBeRc/upload/555926176f3aa1f699a411a3e33e148e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While watching the recent <a target="_blank" href="https://www.youtube.com/watch?v=CLkxRnRQtDE">Tailwind Connect</a> recording, I discovered a new utility class named <code>accent-lime-400</code> . I'd never seen this one, but after some digging, I think it's pretty cool and helps make UIs more consistent with the brand theming.</p>
<p>You can change the style of all checkboxes with a simple line of code:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"checkbox"</span>]</span> {
  <span class="hljs-attribute">accent-color</span>: <span class="hljs-number">#a3e635</span>; <span class="hljs-comment">/* lime-green */</span>
}
</code></pre>
<p>Checking <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/accent-color#browser_compatibility">MDN Web Docs</a>, the browser support is pretty good too, so unless you're worrying about IE11, you should be free to use this as you wish.</p>
]]></content:encoded></item><item><title><![CDATA[Inverted thinking]]></title><description><![CDATA[I just finished watching a video on how to improve problem-solving by "thinking backwards" which I thought was a rather interesting approach.
Inspired by German Mathematician Carl Jacobi, who wrote "invert, always invert", it suggests an alternative ...]]></description><link>https://chris-seaton.co.uk/inverted-thinking</link><guid isPermaLink="true">https://chris-seaton.co.uk/inverted-thinking</guid><category><![CDATA[Problem Solving]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Thu, 20 Jul 2023 14:33:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/df8Fg42fY_0/upload/67cfa7342fda5a69a6d49bc598234fe7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I just finished watching <a target="_blank" href="https://www.linkedin.com/learning/how-to-think-better-by-thinking-backwards/introduction-to-inversion-thinking-15598870">a video</a> on how to improve problem-solving by "thinking backwards" which I thought was a rather interesting approach.</p>
<p>Inspired by German Mathematician Carl Jacobi, who wrote "<em>invert, always invert"</em>, it suggests an alternative method for tackling problems. Rather than identifying what you need to do in order to achieve a goal, first identify what outcomes you wish to avoid. These outcomes can then provide you with prompts on mistakes to avoid when you begin.</p>
<p>For example, take running a marathon. You could simply say "I'll start running a little bit further every day until I reach the 23-mile target". With inverted thinking, you identify the potential issues, things you absolutely wish to avoid:</p>
<ul>
<li><p>What if I hurt myself?</p>
</li>
<li><p>What if I doubt my capabilities, or worse, quit?</p>
</li>
<li><p>What if my training programme isn't suited for me?</p>
</li>
<li><p>What if I eat the wrong food?</p>
</li>
</ul>
<p>With some of these prompts in mind, you can now start to look at solutions:</p>
<ul>
<li><p>Find a good warm-up/warm-down routine</p>
</li>
<li><p>Find a running partner or group to train with, to ensure accountability</p>
</li>
<li><p>Research a training programme that suits my current running experience</p>
</li>
<li><p>Research an appropriate diet to ensure my body is receiving the right fuel</p>
</li>
</ul>
<p>On a similar note, historically I've always recommended people work backwards when tracking down a bug. For example, let's assume you're working on a bug report where a customer claimed they made a purchase but was never fulfilled. They didn't receive a confirmation email. You could tackle this by attempting to recreate the user journey from the very start, but you're immediately hit with questions like:</p>
<ul>
<li><p>How did they add the product to their basket?</p>
</li>
<li><p>Did they receive an email?</p>
</li>
</ul>
<p>And so on. However, you could also see if an email was sent, if a payment was made, or if the order was stored in the database. Rather than working through multiple execution paths, you'll find yourself working on a more tightly scoped problem area, making triaging issues much faster.</p>
]]></content:encoded></item><item><title><![CDATA[TypeScript utility types: omit and pick]]></title><description><![CDATA[As is in the name, at the heart of everything TypeScript offers, are types. As you pass around data, having a predictable structure helps not only reduce run-time errors but also improves developer productivity as you have IntelliSense support in you...]]></description><link>https://chris-seaton.co.uk/typescript-utility-types-omit-and-pick</link><guid isPermaLink="true">https://chris-seaton.co.uk/typescript-utility-types-omit-and-pick</guid><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Thu, 20 Jul 2023 08:56:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/RAK2Dxd0kxg/upload/81f066d6f055aeac078f0f62c065757a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As is in the name, at the heart of everything TypeScript offers, are types. As you pass around data, having a predictable structure helps not only reduce run-time errors but also improves developer productivity as you have IntelliSense support in your favourite IDE.</p>
<p>However, sometimes you only want a subset of data from a larger object, which is where TypeScript's utility types come in:</p>
<ul>
<li><p><code>Omit</code></p>
</li>
<li><p><code>Pick</code></p>
</li>
</ul>
<p>These let you create new types based on an existing type, but filtering in/out specific properties:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">type</span> User = {
  username: <span class="hljs-built_in">string</span>;
  firstName: <span class="hljs-built_in">string</span>;
  lastName: <span class="hljs-built_in">string</span>;
  emailAddress: <span class="hljs-built_in">string</span>;
  avatarUrl: <span class="hljs-built_in">string</span>;
  address: {
    addressLine1: <span class="hljs-built_in">string</span>;
    addressLine2: <span class="hljs-built_in">string</span>;
  };
  createdAt: <span class="hljs-built_in">Date</span>;
}

<span class="hljs-comment">// Provides only username and avatarUrl properties</span>
<span class="hljs-keyword">type</span> MessageBoardUser = Pick&lt;User, <span class="hljs-string">"username"</span> | <span class="hljs-string">"avatarUrl"</span>&gt;

<span class="hljs-comment">// Provides firstName, lastName, emailAddress and address properties</span>
<span class="hljs-keyword">type</span> ShippingUser = Omit&lt;User, <span class="hljs-string">"username"</span> | <span class="hljs-string">"avatarUrl"</span> | <span class="hljs-string">"createdAt"</span>&gt;
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Searching strings in JavaScript]]></title><description><![CDATA[Everyone loves a good ol' regex, but sometimes it's a bit overkill when you simply want to check for the presence of a basic string inside another. Recently, I learned that JavaScript provides three helpful methods that may remove the need to go for ...]]></description><link>https://chris-seaton.co.uk/searching-strings-in-javascript</link><guid isPermaLink="true">https://chris-seaton.co.uk/searching-strings-in-javascript</guid><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Thu, 20 Jul 2023 08:27:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Sn_Y0jTyS94/upload/da8d469caf5151a72c414569fdccd42e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Everyone loves a good ol' regex, but sometimes it's a bit overkill when you simply want to check for the presence of a basic string inside another. Recently, I learned that JavaScript provides three helpful methods that may remove the need to go for regex.</p>
<ul>
<li><p><code>endsWith()</code></p>
</li>
<li><p><code>includes()</code></p>
</li>
<li><p><code>startsWith()</code></p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> firstName = <span class="hljs-string">"John"</span>;
<span class="hljs-keyword">const</span> emailAddress = <span class="hljs-string">"john.doe@example.com"</span>;

<span class="hljs-built_in">console</span>.log(emailAddress.startsWith(firstName.toLowerCase())); <span class="hljs-comment">// true</span>
<span class="hljs-built_in">console</span>.log(emailAddress.includes(<span class="hljs-string">"@"</span>)); <span class="hljs-comment">// true</span>
<span class="hljs-built_in">console</span>.log(emailAddress.endsWith(<span class="hljs-string">"gmail.com"</span>)); <span class="hljs-comment">// false</span>
</code></pre>
<p>Each of the three methods also accepts a second optional parameter that specifies an offset.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fullName = <span class="hljs-string">"John Doe"</span>;

<span class="hljs-built_in">console</span>.log(fullName.startsWith(<span class="hljs-string">"John"</span>)); <span class="hljs-comment">// true</span>
<span class="hljs-built_in">console</span>.log(fullName.startsWith(<span class="hljs-string">"John"</span>, <span class="hljs-number">4</span>)); <span class="hljs-comment">// false</span>
</code></pre>
<p>Disclaimer: Each of these methods is <strong>case-sensitive</strong>. If you need case insensitivity, I'd recommend either regex or applying <code>.toLowerCase()</code> on both strings - just ensure you're doing it in an immutable fashion.</p>
]]></content:encoded></item><item><title><![CDATA[TypeScript constructor parameter properties]]></title><description><![CDATA[For those with an OOP background, you'll often find yourself instantiating a new object by passing one or more values via the constructor and then setting them as object properties, like so:
class User {
    firstName: string;
    lastName: string;

...]]></description><link>https://chris-seaton.co.uk/typescript-constructor-parameter-properties</link><guid isPermaLink="true">https://chris-seaton.co.uk/typescript-constructor-parameter-properties</guid><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Thu, 20 Jul 2023 08:11:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/wKlgNM0z89o/upload/3e892de83c4c5dbfe8fc1e3d5613edb3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For those with an OOP background, you'll often find yourself instantiating a new object by passing one or more values via the constructor and then setting them as object properties, like so:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> User {
    firstName: <span class="hljs-built_in">string</span>;
    lastName: <span class="hljs-built_in">string</span>;

    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">firstName: <span class="hljs-built_in">string</span>, lastName: <span class="hljs-built_in">string</span></span>) {
        <span class="hljs-built_in">this</span>.firstName = firstName;
        <span class="hljs-built_in">this</span>.lastName = lastName;
    }
}

<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">new</span> User(<span class="hljs-string">"John"</span>, <span class="hljs-string">"Doe"</span>);

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${user.firstName}</span> <span class="hljs-subst">${user.lastName}</span>`</span>); <span class="hljs-comment">// John Doe</span>
</code></pre>
<p>There's absolutely nothing wrong with this approach, however, I often say that the best programmers are the laziest ones*. Did you know you can define the class properties in line with the constructor definition? The following code sample is functionally equivalent to the first.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> User {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">public</span> firstName: <span class="hljs-built_in">string</span>, <span class="hljs-keyword">public</span> lastName: <span class="hljs-built_in">string</span></span>) {}
}

<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">new</span> User(<span class="hljs-string">"John"</span>, <span class="hljs-string">"Doe"</span>);

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${user.firstName}</span> <span class="hljs-subst">${user.lastName}</span>`</span>); <span class="hljs-comment">// John Doe</span>
</code></pre>
<p>You may also modify the parameter scope by using <code>protected</code> and <code>private</code> keywords, as well as marking the property as <code>readonly</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> Account {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">public</span> emailAddress: <span class="hljs-built_in">string</span>, <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> password: <span class="hljs-built_in">string</span></span>) {}
}

<span class="hljs-keyword">const</span> account = <span class="hljs-keyword">new</span> Account(<span class="hljs-string">"john.doe@example.com"</span>, <span class="hljs-string">"hunter2"</span>);

<span class="hljs-built_in">console</span>.log(account.emailAddress); <span class="hljs-comment">// john.doe@example.com</span>

<span class="hljs-comment">// Property 'password' is private and only accessible within class 'Account'</span>
<span class="hljs-built_in">console</span>.log(account.password);
</code></pre>
<p>*From an automation perspective, not from a "don't write tests" view!</p>
]]></content:encoded></item><item><title><![CDATA[Read-only and optional class properties with TypeScript]]></title><description><![CDATA[Looking into creating a class in TypeScript, I came across two tidbits that struck me as really interesting. The first is the ability to mark a class property as read-only, i.e. once initialised, that property cannot be updated. You can do this by si...]]></description><link>https://chris-seaton.co.uk/read-only-and-optional-class-properties-with-typescript</link><guid isPermaLink="true">https://chris-seaton.co.uk/read-only-and-optional-class-properties-with-typescript</guid><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Sun, 09 Jul 2023 21:54:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/PC91Jm1DlWA/upload/2f973014c629aec4a45bef2fbd73517e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Looking into creating a class in TypeScript, I came across two tidbits that struck me as really interesting. The first is the ability to mark a class property as read-only, i.e. once initialised, that property cannot be updated. You can do this by simply pre-pending <code>readonly</code> before the property name.</p>
<p>Secondly, you may define <em>optional</em> properties by appending a <code>?</code> to the end of the property name. Easy as that!</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">class</span> Child {
  <span class="hljs-keyword">readonly</span> name: <span class="hljs-built_in">string</span>;
  age: <span class="hljs-built_in">number</span>;
  nickname?: <span class="hljs-built_in">string</span>; <span class="hljs-comment">// optional</span>

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">name: <span class="hljs-built_in">string</span>, age: <span class="hljs-built_in">number</span>, nickname?: <span class="hljs-built_in">string</span></span>) {
    <span class="hljs-built_in">this</span>.name = name;
    <span class="hljs-built_in">this</span>.age = age;
    <span class="hljs-built_in">this</span>.nickname = nickname;
  }
}

<span class="hljs-keyword">const</span> alice = <span class="hljs-keyword">new</span> Child(<span class="hljs-string">"Alice"</span>, <span class="hljs-number">10</span>);
<span class="hljs-keyword">const</span> bob = <span class="hljs-keyword">new</span> Child(<span class="hljs-string">"Robert"</span>, <span class="hljs-number">5</span>, <span class="hljs-string">"Bob"</span>);

<span class="hljs-built_in">console</span>.log(alice.nickname, bob.nickname); <span class="hljs-comment">// "undefined Bob"</span>
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Literal types with TypeScript]]></title><description><![CDATA[I've been recently brushing up on my TypeScript courtesy of codewithmosh.com's Ultimate TypeScript Course. While explicit types are a concept taken from Page 1 of the TypeScript handbook, today I discovered that you can also increase the strictness o...]]></description><link>https://chris-seaton.co.uk/literal-types-with-typescript</link><guid isPermaLink="true">https://chris-seaton.co.uk/literal-types-with-typescript</guid><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Sat, 08 Jul 2023 21:21:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/vvAtwDoGZxA/upload/01baf695167275334b1f3ee37ab7fb83.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've been recently brushing up on my TypeScript courtesy of codewithmosh.com's <a target="_blank" href="https://codewithmosh.com/p/the-ultimate-typescript"><em>Ultimate TypeScript Course</em></a>. While explicit types are a concept taken from Page 1 of the TypeScript handbook, today I discovered that you can also increase the strictness of a variable even further with <a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types">literal types</a>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// This can *only* be "heads" or "tails"</span>
<span class="hljs-keyword">type</span> Coin = <span class="hljs-string">"heads"</span> | <span class="hljs-string">"tails"</span>; 

<span class="hljs-keyword">const</span> flip = (): <span class="hljs-function"><span class="hljs-params">Coin</span> =&gt;</span> <span class="hljs-built_in">Math</span>.random() &lt; <span class="hljs-number">0.5</span> ? <span class="hljs-string">"heads"</span> : <span class="hljs-string">"tails"</span>;

<span class="hljs-built_in">console</span>.log(flip());
</code></pre>
<p>Obviously, there is a lot of similarity to using an <code>enum</code> , but has the benefit of generating <em>slightly</em> less code after compilation if that's your bag. Personally, I'd probably stick with a backed <a target="_blank" href="https://www.typescriptlang.org/docs/handbook/enums.html">enum</a>:</p>
<pre><code class="lang-typescript"><span class="hljs-built_in">enum</span> Coin {
  HEADS = <span class="hljs-string">"heads"</span>,
  TAILS = <span class="hljs-string">"tails"</span>,
}

<span class="hljs-keyword">const</span> flip = (): <span class="hljs-function"><span class="hljs-params">Coin</span> =&gt;</span> (<span class="hljs-built_in">Math</span>.random() &lt; <span class="hljs-number">0.5</span> ? Coin.HEADS : Coin.TAILS);

<span class="hljs-built_in">console</span>.log(flip());
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Private properties in JavaScript]]></title><description><![CDATA[As someone that learned Java at university, then became a full-time PHP code monkey, I've taken property visibility for granted. You don't want people to directly read or write an object's property, no problem! Slap private in front of it and sleep s...]]></description><link>https://chris-seaton.co.uk/private-properties-in-javascript</link><guid isPermaLink="true">https://chris-seaton.co.uk/private-properties-in-javascript</guid><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Sat, 01 Jul 2023 21:05:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/u5Zt-HoocrM/upload/10db8830c991bbb3d839059dfaa4eef7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As someone that learned Java at university, then became a full-time PHP code monkey, I've taken property visibility for granted. You don't want people to directly read or write an object's property, no problem! Slap <code>private</code> in front of it and sleep soundly at night knowing you've done a great job.</p>
<p>Well, unless you're working with JavaScript*. But don't worry, there is a way to give you the control you need without too much effort.</p>
<p>Below shows the creation of an employee named John Doe who gets paid 10,000 simoleons (since he lives in SimCity, naturally). The <code>Employee</code> function takes an object with two properties - <code>name</code> and <code>salary</code> , and stores them as local variables. Finally, with a sprinkling of <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures">closure magic</a>, it returns a new object with 2 getters and a single setter. These three functions are the only ways to interact with the employee object, meaning direct access to <code>_name</code> and <code>_salary</code> are prohibited.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Employee = <span class="hljs-function">(<span class="hljs-params">{ name, salary }</span>) =&gt;</span> {
    <span class="hljs-keyword">let</span> _name = name;
    <span class="hljs-keyword">let</span> _salary = salary;

    <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">getName</span>: <span class="hljs-function">() =&gt;</span> _name,
        <span class="hljs-attr">getSalary</span>: <span class="hljs-function">() =&gt;</span> _salary,
        <span class="hljs-attr">setSalary</span>: <span class="hljs-function">(<span class="hljs-params">newSalary</span>) =&gt;</span> _salary = newSalary
    }
};

<span class="hljs-keyword">const</span> johnDoe = Employee({<span class="hljs-attr">name</span>: <span class="hljs-string">"John Doe"</span>, <span class="hljs-attr">salary</span>: <span class="hljs-number">10000</span> });
johnDoe.getName(); <span class="hljs-comment">// "John Doe"</span>
johnDoe.getSalary(); <span class="hljs-comment">// 10000</span>
johnDoe.setSalary(<span class="hljs-number">12000</span>);
johnDoe.getSalary(); <span class="hljs-comment">// 12000</span>
</code></pre>
<p>* No prefixing all property names with a <code>_</code> won't save you</p>
]]></content:encoded></item><item><title><![CDATA[Populating all values in an array]]></title><description><![CDATA[I was recently tinkering away with JavaScript, when I needed to quickly fill an array with a default value of 0. At the risk of showing my age and JavaScript naivety, I naturally reached for a for loop:
const list = [];

for (let i = 0; i < 10; i++) ...]]></description><link>https://chris-seaton.co.uk/populating-all-values-in-an-array</link><guid isPermaLink="true">https://chris-seaton.co.uk/populating-all-values-in-an-array</guid><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Sat, 01 Jul 2023 20:37:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/XWDMmk-yW7Q/upload/7365ca6681726c0643b6775a85cc82ed.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was recently tinkering away with JavaScript, when I needed to quickly fill an array with a default value of <code>0</code>. At the risk of showing my age and JavaScript naivety, I naturally reached for a <code>for</code> loop:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> list = [];

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++) {
    list[i] = <span class="hljs-number">0</span>;
}

<span class="hljs-comment">// [0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0]</span>
</code></pre>
<p>This is fine and will do what I need. However, one of the benefits of JavaScript these days is the syntactic sugar that has been added in more recent releases of ECMAScript. So why not take advantage of <code>Array.fill()</code>?</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> list = <span class="hljs-built_in">Array</span>(<span class="hljs-number">10</span>).fill(<span class="hljs-number">0</span>);

<span class="hljs-comment">// [0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0]</span>
</code></pre>
<p>The <code>fill()</code> method also accepts two further, optional parameters to define the starting and ending indexes. For example, the code below states that we should set the fifth through ninth values of the <code>list</code> array with a <code>0</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> list = <span class="hljs-built_in">Array</span>(<span class="hljs-number">10</span>).fill(<span class="hljs-number">0</span>, <span class="hljs-number">5</span>, <span class="hljs-number">10</span>);

<span class="hljs-comment">// [5: 0, 6: 0, 7: 0, 8: 0, 9: 0]</span>
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Counting the number of occurrences in a string using a higher-order function]]></title><description><![CDATA[I was recently working on some code that required me to count the number of occurrences of an @ in a string. Initially, I created the following:
const matches = (email.match("@")||[]).length;

However, the ||[] which defaults to an empty array if no ...]]></description><link>https://chris-seaton.co.uk/counting-the-number-of-occurrences-in-a-string-using-a-higher-order-function</link><guid isPermaLink="true">https://chris-seaton.co.uk/counting-the-number-of-occurrences-in-a-string-using-a-higher-order-function</guid><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Thu, 29 Jun 2023 12:37:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/a124Ay5qgU8/upload/ff44e50d0c60982622fcbc58e42ab77a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was recently working on some code that required me to count the number of occurrences of an <code>@</code> in a string. Initially, I created the following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> matches = (email.match(<span class="hljs-string">"@"</span>)||[]).length;
</code></pre>
<p>However, the <code>||[]</code> which defaults to an empty array if no <code>@</code> characters are found strikes me as rather hard to read. Looking for alternatives, I found that you could use <code>filter()</code> instead:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> matches = [...email].filter(<span class="hljs-function"><span class="hljs-params">char</span> =&gt;</span> char === <span class="hljs-string">"@"</span>).length
</code></pre>
<p>I'm not convinced this is much clearer, but it's always good to see how other people tackle the same problem, you'll always learn new things.</p>
]]></content:encoded></item><item><title><![CDATA[useEffect Cleanup Functions]]></title><description><![CDATA[As a Vue.js fanboy, I've largely ignored what's been going on in the React ecosystem for far too many years, and so now I find myself cramming every possible React tutorial under the sun to get a better understanding of how it works.
Today I have bee...]]></description><link>https://chris-seaton.co.uk/useeffect-cleanup-functions</link><guid isPermaLink="true">https://chris-seaton.co.uk/useeffect-cleanup-functions</guid><category><![CDATA[React]]></category><dc:creator><![CDATA[Chris S]]></dc:creator><pubDate>Thu, 29 Jun 2023 10:07:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/hSODeSbvzE0/upload/2f90d91369b3d2217678d85bbd439418.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a Vue.js fanboy, I've largely ignored what's been going on in the React ecosystem for far too many years, and so now I find myself cramming every possible React tutorial under the sun to get a better understanding of how it works.</p>
<p>Today I have been working my way through Ali Spittel's <a target="_blank" href="https://www.linkedin.com/learning/react-js-code-challenges">React.js Coding Challenges</a> over on LinkedIn Learning to put what I've learned so far to the test. The challenge in question was to add a double-click listener to the window when a toggle button is clicked, then remove it again once the toggle button is clicked again.</p>
<p>Once I'd finished the task, I watch the solution and discovered that you can return a function from inside the setup function of a <code>useEffect</code> hook:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">windowEvent</span>(<span class="hljs-params"></span>) </span>{
    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> handleDblClick = <span class="hljs-function">() =&gt;</span> alert(<span class="hljs-string">"mouse pressed"</span>);
        <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"dblclick"</span>, handleDblClick);

        <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">"dblclick"</span>, handleDblClick);
    });
}
</code></pre>
<p>I'd never seen this before, but it turns out that this method is known as a <em>clean-up function</em>, which is executed when the component is re-rendered, before running the setup method again.</p>
]]></content:encoded></item></channel></rss>