VitaneriVincent Taneri's blog and portfoliohttps://vitaneri.com/en-usBetter React Context DX With Custom Provider And Consumer Hookhttps://vitaneri.com/posts/better-react-context-dx-with-custom-provider-and-consumer-hook/https://vitaneri.com/posts/better-react-context-dx-with-custom-provider-and-consumer-hook/Abstracting React's Context API using custom provider and consumer hook.Fri, 20 Jan 2023 08:43:41 GMT<p>In this post, we'll take a look at how we can abstract React's context API using custom provider and consumer hook for a better developer experience.</p> <h2>Introduction</h2> <p>React's Context API is amazing. One of it's use is allowing us to pass data through our component trees without prop drilling, resulting in a much cleaner code.</p> <p>But do you know that we can make it even better by abstracting the implementation of the context with custom provider and consumer hook?</p> <p>Let's look at how we can do that.</p> <p>Assume that we are using React's context API to manage the site's theme.</p> <h2>Custom Provider</h2> <p>We start by creating a theme context. We export the context because our child components will have to import it to access the context.</p> <pre><code>export const ThemeContext = createContext(); </code></pre> <p>Now that we have the context, we can create a custom provider so that we can wrap our app with <code>ThemeProvider</code> instead of <code>ThemeContext.Provider</code>.</p> <pre><code>import { createContext, useState } from "react"; export const ThemeContext = createContext(); export default ThemeProvider = (props) =&gt; { const [theme, setTheme] = useState("light"); const toggleTheme = () =&gt; { setTheme(theme === "light" ? "dark" : "light"); }; const color = theme === "light" ? "#333" : "#FFF"; const backgroundColor = theme === "light" ? "#FFF" : "#333"; document.body.style.color = color; document.body.style.backgroundColor = backgroundColor; return &lt;ThemeContext.Provider value={{ theme, toggleTheme }} {...props} /&gt;; }; </code></pre> <p>Assuming that the whole app need to access this context, we can wrap our <code>&lt;App /&gt;</code> component in <code>index.ts</code> like this:</p> <pre><code>import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; import { ThemeProvider } from "./ThemeProvider"; ReactDOM.render( &lt;ThemeProvider&gt; &lt;App /&gt; &lt;/ThemeProvider&gt;, document.getElementById("root"), ); </code></pre> <h2>Consumer Hook</h2> <p>Now, let's look at the button component that toggles the site theme. To do that, the button will have to access the <code>ThemeContext</code> using React's <code>useContext</code> hook.</p> <pre><code>import { useContext } from "react"; import { ThemeContext } from "./ThemeProvider"; export default ToggleThemeBtn() { // We can access the context using React's "useContext" hook const { theme, toggleTheme } = useContext(ThemeContext); return ( &lt;button onClick={toggleTheme}&gt; {theme === 'light' ? 'dark' : 'light'} mode &lt;/button&gt; ); }; </code></pre> <p>Everything is working properly, we can toggle the site's theme just fine. But the way we are accessing the <code>ThemeContext</code> can use some improvement. Instead of <code>useContext(ThemeContext)</code>, wouldn't it be better if we can access the site's theme and its toggle function with an API like <code>useTheme()</code> instead?</p> <pre><code>const { theme, toggleTheme } = useTheme(); </code></pre> <p>To implement this, let's create a custom hook in our <code>ThemeProvider.jsx</code> file.</p> <pre><code>import { createContext, useContext, useState } from "react"; export const ThemeContext = createContext(); export const useTheme = () =&gt; { const { theme, toggleTheme } = useContext(ThemeContext); }; export default ThemeProvider = (props) =&gt; { const [theme, setTheme] = useState("light"); const toggleTheme = () =&gt; { setTheme(theme === "light" ? "dark" : "light"); }; const color = theme === "light" ? "#333" : "#FFF"; const backgroundColor = theme === "light" ? "#FFF" : "#333"; document.body.style.color = color; document.body.style.backgroundColor = backgroundColor; return &lt;ThemeContext.Provider value={{ theme, toggleTheme }} {...props} /&gt;; }; </code></pre> <p>And we also don't have to export <code>ThemeContext</code> anymore since that's considered an implementation detail now.</p> <pre><code>import { createContext, useContext, useState } from "react"; const ThemeContext = createContext(); export useTheme = () =&gt; { const themeContext = useContext(ThemeContext); return themeContext; }; export default ThemeProvider = (props) =&gt; { const [theme, setTheme] = useState("light"); const toggleTheme = () =&gt; { setTheme(theme === "light" ? "dark" : "light"); }; const color = theme === "light" ? "#333" : "#FFF"; const backgroundColor = theme === "light" ? "#FFF" : "#333"; document.body.style.color = color; document.body.style.backgroundColor = backgroundColor; return &lt;ThemeContext.Provider value={{ theme, toggleTheme }} {...props} /&gt;; }; </code></pre> <p>And finally, in our button component:</p> <pre><code>import { useTheme } from "./ThemeProvider"; export default ToggleThemeBtn() { const { theme, toggleTheme } = useTheme(); return ( &lt;button onClick={toggleTheme}&gt; {theme === 'light' ? 'dark' : 'light'} mode &lt;/button&gt; ); }; </code></pre> <p>Don't you agree that it's much cleaner now? And of course we can improve the hook even more.</p> <p>Say that someone use our button outside <code>ThemeProvider</code>. When that happens, our app will crash because the context will return <code>undefined</code>.</p> <p>Usually, when accessing the context directly, people will check if the context is <code>undefined</code> to tackle this issue.</p> <pre><code>import { useContext } from "react"; import { ThemeContext } from "./ThemeProvider"; export default ToggleThemeBtn() { const { theme, toggleTheme } = useContext(ThemeContext); if (!theme) { // handle error } return ( &lt;button onClick={toggleTheme}&gt; {theme === 'light' ? 'dark' : 'light'} mode &lt;/button&gt; ); }; </code></pre> <p>That's indeed a valid solution. But imagine that we have multiple components doing this 🥲.</p> <p>But with our custom hook solution, we can just handle that inside the hook.</p> <pre><code>export const useTheme = () =&gt; { const themeContext = useContext(ThemeContext); if (!themeContext) { throw new Error("ThemeContext is undefined. Make sure to wrap your component with ThemeProvider."); } return themeContext; }; </code></pre> <h2>Wrap Up</h2> <p>That's it for this post. Hope you can see the appeal of this pattern, creating a custom provider and consumer hook instead of accessing the context directly.</p> reactjavascriptVincent TaneriCheck For Nil Interface In Gohttps://vitaneri.com/posts/check-for-nil-interface-in-go/https://vitaneri.com/posts/check-for-nil-interface-in-go/A short guide on checking for nil interface in Go.Mon, 14 Nov 2022 16:07:52 GMT<p>The zero value for a Go interface is <code>nil</code>. But unlike the <code>nil</code> for concrete types (e.g: pointer, slice), checking for <code>nil</code> interface is not as straightforward.</p> <p>In this post, we'll look at how we can check if an interface is <code>nil</code> using the <code>reflect</code> package.</p> <h2>The Problem</h2> <p>First, check out the following code snippet:</p> <pre><code>var a []int fmt.Println(a == nil) // prints true var s *string fmt.Println(s == nil) // prints true var i interface{} fmt.Println(i == nil) // prints true i = s fmt.Println(i == nil) // prints false </code></pre> <p>The last line will always prints false, and go-staticcheck will give us a warning.</p> <pre><code>this comparison is never true; the lhs of the comparison has been assigned a concretely typed value </code></pre> <p>Under the hood, Go's interfaces are a pair of pointers. One points to the underlying type and one points to the underlying value.</p> <p>In this case, because we assign a value that's <em>concretely typed</em> to <code>i</code>, the interface is no longer <code>nil</code>, even though the assigned value is <code>nil</code>.</p> <p>Or to word it a little differently, if a <code>nil</code> variable with a concrete type is assigned to a variable with an interface type, the interface type is definitely not <code>nil</code>.</p> <blockquote> <p>An interface is only considered <code>nil</code> when both its type and value are <code>nil</code>.</p> </blockquote> <h2>Solution</h2> <p>To reliably check if the value associated with an interface is <code>nil</code>, we need two use the <code>isValid</code> and <code>isNil</code> methods from <code>reflection</code>.</p> <pre><code>func checkNilInterface(i interface{}) bool { iv := reflect.ValueOf(i) if !iv.IsValid() { return true } switch iv.Kind() { case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Func, reflect.Interface: return iv.IsNil() default: return false } } </code></pre> <p>The <code>IsValid</code> check on line 3 returns <code>true</code> if <code>iv</code> is not a <code>nil</code> interface.</p> <p>Next we check whether the value associated with the interface is <code>nil</code> using the <code>IsNil</code> method. Note that the <code>IsNil</code> method can only be called on a type that can contain <code>nil</code>, thence the case statement above it.</p> <h2>Wrap Up</h2> <p>That's how you can check for <code>nil</code> interface in Go. Before we end this post, let's see how the checker function does with our initial example.</p> <pre><code>var a []int fmt.Println(a == nil) // prints true var s *string fmt.Println(s == nil) // prints true var i interface{} fmt.Println(i == nil) // prints true fmt.Println(checkNilInterface(i)) // prints true i = s fmt.Println(i == nil) // prints false fmt.Println(checkNilInterface(i)) // prints true </code></pre> goVincent TaneriCode Splitting In React Using React.lazy and React.Suspensehttps://vitaneri.com/posts/code-splitting-in-react-using-reactlazy-and-reactsuspense/https://vitaneri.com/posts/code-splitting-in-react-using-reactlazy-and-reactsuspense/A guide on how to code split in React using React.lazy and React.Suspense.Sun, 22 Jan 2023 15:51:52 GMT<p>In this post, we will learn how to do code splitting in our React app using <code>React.lazy</code> and <code>React.suspense</code>.</p> <h2>Introduction</h2> <p>As we add more features to our React app, our app will get more and more bloated, resulting in bigger bundle size. Is there a way to minimize the bundle size while adding features to our app? <em>Code Splitting</em> to the rescue 💪🏻.</p> <p>Code splitting allows us to load our app with <em>lazy-loaded</em> chunks. The idea is that we try to only load what's necessary for the user on initial load, and lazy-load the rest of our app when needed.</p> <p>Imagine that you have a long blog post with multiple images. When the user load your page initially, it's a good idea to only load the featured image the user see, and load the rest of the images as the user scroll down. Images are usually pretty large in size, and lazy-loading them is a good idea.</p> <p>Of course we're not limited to lazy-loading images, we can lazy-load anything, including codes. It's usually a good idea to lazy-load expensive component like graph, map, etc. You got the idea.</p> <p>Code splitting won't magically reduce our app's overall bundle size, but it can potentially cut off our initial bundle size significantly when used correctly, resulting in better UX.</p> <p>To accomplish this task in React, we need to use <code>React.lazy</code> and <code>React.Suspense</code>.</p> <h2>React.lazy</h2> <p><code>React.lazy</code> as the name suggests, allows us to import component lazily or dynamically. In other word, it allow components to be loaded <em>on demand</em>.</p> <p>So how do we use it?</p> <p>Let's first look at the example that we will use for the rest of the post.</p> <p>Say that we have a toggle that hide and show a graph.</p> <pre><code>import * as React from "react" import Graph from "./Components/Graph" export default function Toggle { const [showGraph, setShowGraph] = React.useState(false) return ( &lt;&gt; &lt;Switch on={showGraph} onClick={() =&gt; setShowGraph(!showGraph)} /&gt; &lt;div&gt; { showGraph ? &lt;Graph /&gt; : null} &lt;/div&gt; &lt;/&gt; ) } </code></pre> <p>In the code above, even though the <code>&lt;Graph /&gt;</code> component is initially not rendered, the code for it is still requested and downloaded by the browser. This is not ideal.</p> <p>Let's assume that the <code>&lt;Graph /&gt;</code> component is pretty expensive and we want to lazy-load it instead. We want the code for it to be downloaded only when the user click on the switch and <code>showGraph === true</code>.</p> <p>We can do it using <code>React.lazy</code> like this:</p> <pre><code>import * as React from "react" const Graph = React.lazy(() =&gt; import("./Components/Graph")) export default function Toggle { const [showGraph, setShowGraph] = React.useState(false) return ( &lt;&gt; &lt;Switch on={showGraph} onClick={() =&gt; setShowGraph(!showGraph)} /&gt; &lt;div&gt; { showGraph ? &lt;Graph /&gt; : null} &lt;div&gt; &lt;/&gt; ) } </code></pre> <blockquote> <p>Note that for this to work, the Graph component have to be a default export (<code>export default Graph</code> in <code>Graph.jsx</code>).</p> </blockquote> <p>Now, the <code>&lt;Graph /&gt;</code> component will be lazily-loaded when it's about to render.</p> <p>But now, if you go to your browser and click on the switch, you'll see a white screen of the death 😰 instead.</p> <p>This is because <code>React.lazy</code> need to be used in conjunction with <code>React.Suspense</code>. And so, on to the next section we go.</p> <h2>React.Suspense</h2> <p>We need to wrap our lazy-loaded components inside <code>React.Suspense</code> for them to work properly.</p> <pre><code>import * as React from "react" const Graph = React.lazy(() =&gt; import("./Components/Graph")) export default function Toggle { const [showGraph, setShowGraph] = React.useState(false) return ( &lt;&gt; &lt;Switch on={showGraph} onClick={() =&gt; setShowGraph(!showGraph)} /&gt; &lt;div&gt; &lt;React.Suspense&gt; { showGraph ? &lt;Graph /&gt; : null} &lt;/React.Suspense&gt; &lt;div&gt; &lt;/&gt; ) } </code></pre> <p>Now our app work as expected. But we can make the UX even better by providing a fallback component in <code>React.Suspense</code>.</p> <pre><code>import * as React from "react" import LoadingIndicator from "./Components/LoadingIndicator" const Graph = React.lazy(() =&gt; import("./Components/Graph")) export default function Toggle { const [showGraph, setShowGraph] = React.useState(false) return ( &lt;&gt; &lt;Switch on={showGraph} onClick={() =&gt; setShowGraph(!showGraph)} /&gt; &lt;div&gt; &lt;React.Suspense fallback={&lt;LoadingIndicator /&gt;}&gt; { showGraph ? &lt;Graph /&gt; : null} &lt;/React.Suspense&gt; &lt;div&gt; &lt;/&gt; ) } </code></pre> <p>With this addition, when the user click the switch and the browser start fetching the code for <code>&lt;Graph /&gt;</code>, the <code>&lt;LoadingIndicator /&gt;</code> component will be shown in its place as a placeholder.</p> <h2>Prefetching</h2> <p>We can improve the UX a step further by prefetching the code when the user show signs of clicking the switch. One thing that come to mind is when the user hover over the switch.</p> <p>Prefetching can save us some milliseconds, but that's enough to make the difference between a fast and a clunky app.</p> <p>One way to implement this is using the <code>mouseenter</code> event listener:</p> <pre><code>import * as React from "react" import LoadingIndicator from "./Components/LoadingIndicator" const Graph = React.lazy(() =&gt; import("./Components/Graph")) export default function Toggle { const [showGraph, setShowGraph] = React.useState(false) return ( &lt;&gt; &lt;Switch on={showGraph} onClick={() =&gt; setShowGraph(!showGraph)} onMouseEnter={() =&gt; import("./Components/Graph")} /&gt; &lt;div&gt; &lt;React.Suspense fallback={&lt;LoadingIndicator /&gt;}&gt; { showGraph ? &lt;Graph /&gt; : null} &lt;/React.Suspense&gt; &lt;div&gt; &lt;/&gt; ) } </code></pre> <p>That's it!</p> <p>You might be wondering about whether it's actually fine to import the same component multiple times like we did above. The answer is that it's actually fine because browser will cache the imported components.</p> <p>In the scenario above, when the user hover over the switch, we start importing the <code>&lt;Graph /&gt;</code> component. And when the user finally click on the switch. This line of code: <code>React.lazy(() =&gt; import("./Components/Graph"))</code> will still run, but the component in the cache will be returned instead.</p> <h2>Wrap Up</h2> <p>Finally, let's do some refactoring to reduce code duplication.</p> <pre><code>import * as React from "react" import LoadingIndicator from "./Components/LoadingIndicator" const loadGraph = () =&gt; import("./Components/Graph") const Graph = React.lazy(loadGraph) export default function Toggle { const [showGraph, setShowGraph] = React.useState(false) return ( &lt;&gt; &lt;Switch on={showGraph} onClick={() =&gt; setShowGraph(!showGraph)} onMouseEnter={loadGraph} /&gt; &lt;div&gt; &lt;React.Suspense fallback={&lt;LoadingIndicator /&gt;}&gt; { showGraph ? &lt;Graph /&gt; : null} &lt;/React.Suspense&gt; &lt;div&gt; &lt;/&gt; ) } </code></pre> <p>That's it for this post. Hope you can see how easy it is to implement code splitting and it's benefit on performance and UX.</p> javascriptreactVincent TaneriEnforce String Casing in TypeScript: Creating Uppercase, Lowercase, and Capitalized String Typeshttps://vitaneri.com/posts/enforce-string-casing-in-typescript-creating-uppercase-lowercase-and-capitalized-string-types/https://vitaneri.com/posts/enforce-string-casing-in-typescript-creating-uppercase-lowercase-and-capitalized-string-types/A little trick to create type that only allow uppercase, lowercase, or capitalized string in Typescript.Fri, 23 Jun 2023 11:12:30 GMT<p>In this post, I'll share a little trick to create type that only allow uppercase, lowercase, or capitalized string in Typescript using intrinsic string manipulation types in Typescript.</p> <p>What we want to achieve:</p> <pre><code>const str: IsUppercase = "hello"; // we want this line to error </code></pre> <h2>Intrinsic String Manipulation Types</h2> <p>Before showing the solution, I would like to introduce you to <strong>Intrinsic String Manipulation Types</strong> that're built into Typescript itself.</p> <h3>Uppercase</h3> <p>This utility type converts each character in the string to the uppercase version.</p> <pre><code>type Greeting = "Hello, world"; type ShoutyGreeting = Uppercase&lt;Greeting&gt;; // type ShoutyGreeting = "HELLO, WORLD" </code></pre> <h3>Lowercase</h3> <p>This utility type converts each character in the string to the lowercase version.</p> <pre><code>type Greeting = "Hello, world"; type ListlessGreeting = Lowercase&lt;Greeting&gt;; // type ListlessGreeting = "hello, world" </code></pre> <h3>Capitalize</h3> <p>This utility converts <em>only</em> the first character in the string to uppercase.</p> <pre><code>type Greeting = "hello, world"; type CapitalizedGreeting = Capitalize&lt;Greeting&gt;; // type CapitalizedGreeting = "Hello, world" </code></pre> <h2>Enforcing String Casing</h2> <p>Now, an interesting use case for those helper function is to enforce casing for the <code>string</code> type.</p> <p>Back to our original example, we can implement <code>IsUppercase</code> type this way:</p> <pre><code>type IsUppercase = Uppercase&lt;string&gt;; </code></pre> <p>and the <code>str</code> will error when passed lowercase string</p> <pre><code>const a: IsUppercase = "aa"; // Type 'string' is not assignable to type 'Uppercase&lt;string&gt;' const a2: IsUppercase = "AA"; // OK </code></pre> <p>The same idea apply for both <code>IsLowercase</code> and <code>IsCapitalized</code> too.</p> <pre><code>type IsLowercase = Lowercase&lt;string&gt;; type IsCapitalized = Capitalize&lt;string&gt;; const b: IsLowercase = "bB"; // Type 'string' is not assignable to type 'Lowercase&lt;string&gt;' const b2: IsLowercase = "bb"; // OK const c: IsCapitalized = "cC"; // Type 'string' is not assignable to type 'Capitalize&lt;string&gt;' const c2: IsCapitalized = "Cc"; //OK </code></pre> <h2>Wrap Up</h2> <p>That's it for the article, hope you find this little trick useful.</p> typescriptVincent TaneriEnums In TypeScripthttps://vitaneri.com/posts/enums-in-typescript/https://vitaneri.com/posts/enums-in-typescript/Introduction to Enums in TypeScript.Sat, 15 Oct 2022 01:35:13 GMT<p>Enums is a special type whose concept will already be familiar to you if you come from languages like C#, C++, Java, etc.</p> <p>In this post, we'll look at how enums work in TypeScript, and also how the TypeScript compiler compile enums to plain JavaScript. After all, enums doesn't exist natively in the JavaScript world.</p> <h2>Enums</h2> <p>Enums are used to define a human-readable name for numbers or strings with specific meaning.</p> <p>This is how you declare an enums in TypeScript:</p> <pre><code>enum ModalState { Open, Closed, } </code></pre> <p>Now, let's look at how we can use this enums.</p> <pre><code>function checkModalState(state: ModalState) { console.log(`Enum's real value is: ${state}`); switch (state) { case ModalState.Open: console.log("Modal is open."); break; case ModalState.Closed: console.log("Door is closed."); break; } } </code></pre> <p>So, we start by declaring an enum called <code>ModalState</code>. This enum has two possible values, <code>Open</code> and <code>Closed</code>. We then created a function called <code>checkModalState</code> that take a single argument called <code>state</code> of type <code>ModalState</code>. This means that we can only call this function with one of the values of the <code>ModalState</code> enum.</p> <p>The function logs the actual value of the <code>state</code> parameter to the console then executes a <code>switch</code> statement. The <code>switch</code> statements logs a message to the console depending on the value of the <code>state</code> parameter we passed in.</p> <p>Let's run the function with the following code.</p> <pre><code>checkModalState(ModalState.Open); checkModalState(ModalState.Closed); </code></pre> <p>The output of this code is as follows:</p> <pre><code>Enum's real value is: 0 Modal is open. Enum's real value is: 1 Modal is closed. </code></pre> <p>As you can see, the TypeScript compiler has generated a numerical value for all the values in our enum. The value for <code>ModalState.Open</code> is <code>0</code>, and the value for <code>ModalState.Closed</code> is <code>1</code>.</p> <p>Enums eliminates the so called magic numbers by defining a clear possible values. Enums helps us provide a clear set of values for a variable or function parameter. Like in the example above, we can only pass <code>ModalState.Open</code> or <code>ModalState.Closed</code> to our function.</p> <p>We can also set the numerical value of an enum to whatever we like. For example:</p> <pre><code>enum ModalState { Open = 5, Closed = 10, } </code></pre> <p>Now, if we run the <code>checkModalState</code> function again.</p> <pre><code>checkModalState(ModalState.Open); checkModalState(ModalState.Closed); </code></pre> <p>We'll get the following output:</p> <pre><code>Enum's real value is: 5 Modal is open. Enum's real value is: 10 Modal is closed. </code></pre> <h2>Strings Enums</h2> <p>In TypeScript, we are not limited to numeric enums. We can also use a string enum. Let's look at an example.</p> <pre><code>enum ModalState { OPEN = "Open", CLOSED = "Closed", } </code></pre> <p>Now, let's <code>console.log()</code> the value.</p> <pre><code>console.log(`OPEN = ${ModalState.OPEN}`); </code></pre> <p>As expected, TypeScript compiler is resolving the enum value to the <code>Open</code> string.</p> <pre><code>OPEN = Open </code></pre> <p>String enums don't auto-increment like the numeric enum. You've got to assign a value to all the other enum values the moment you assign a value to one.</p> <pre><code>enum modalState { OPEN = "open", Closed, // TypeScript will complain about this line } </code></pre> <p>You can also make a heterogenous enums like this, but it's generally not recommended.</p> <pre><code>enum modalState { OPEN = 1, CLOSED = "Closed", } </code></pre> <p>String enum is particularly useful when we're debugging. Unlike the runtime value of numeric enums, the value of string enums convey a meaningful and readable value that'll make our debugging experience much better.</p> <h2>Const Enums</h2> <p>When requirements are tight, and our code has to be as minimal as possible, we can use the const enums by adding the <code>const</code> keyword before the enum definition.</p> <pre><code>const enum ModalState { Open, Closed, } </code></pre> <p>Const enum is introduced for performance reasons. The enums are completely removed during compilation.</p> <p>Before we look at how const enums are implemented in plain JavaScript, let's go back and take a look at the JavaScript implementation of normal enums.</p> <pre><code>enum ModalState { Open, Closed, } </code></pre> <p>This is how the code above look like after compilation.</p> <pre><code>var modalState; (function (modalState) { modalState[(modalState["Open"] = 0)] = "Open"; modalState[(modalState["Closed"] = 1)] = "Closed"; })(modalState || (modalState = {})); </code></pre> <p>Let's ignore the complex-looking JavaScript. The point here is that an object is created by the compiler to represent the enum. If we log the object, we get:</p> <pre><code>{ "0": "Open", "1": "Closed", "Open": 0, "Closed": 1 } </code></pre> <p>Now, back to const enum. No object is generated at all. They are completely removed during compilation.</p> <pre><code>const enum modalState { Open, Closed, } console.log(modalState); // this line will error </code></pre> <p>TypeScript will make this kind of complain if we try to <code>console.log()</code> const enum.</p> <pre><code>'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query. </code></pre> <p>That's understandable because <code>modalState</code>, in this case, is completely removed on the compiled JavaScript code. Const enum are inlined at use sites.</p> <p>To look at the generated JavaScript for a const enum. Let's compile the following code.</p> <pre><code>console.log(modalState.Open); </code></pre> <p>Result of compilation:</p> <pre><code>console.log(0 /* modalState.Open */); </code></pre> <p>As you can see, there is no actual implementation of the enum itself at all. The compiler simply substituted the JavaScript code with the value of the enum and a comment following it (Yes, that comment is generated by the compiler).</p> <p>This reduce the size of the generated code, and the JavaScript runtime doesn't need to work with a JavaScript object in order to check a value resulting in a better performance.</p> <h2>Wrap Up</h2> <p>That's it for the basic of the TypeScript enums. Of course there're still lots of detail that you can read on <a href="https://www.typescriptlang.org/docs/handbook/enums.html">the official docs</a> if you want to understand TypeScript enums even more.</p> typescriptVincent TaneriGuide To Sorting In Gohttps://vitaneri.com/posts/guide-to-sorting-in-go/https://vitaneri.com/posts/guide-to-sorting-in-go/Various ways to sort a slice in using the built-in 'sort' package in Go.Wed, 16 Nov 2022 04:03:59 GMT<p>In this post, we're going to take a look at various ways to sort a slice using the <code>sort</code> package from Go's standard library.</p> <h2>Ascending Sort</h2> <p>To sort a slice in ascending order, we can use the <code>Ints(x)</code>, <code>Float64(x)</code>, and <code>Strings(x)</code> from the <code>sort</code> package.</p> <p>Examples:</p> <ul> <li>Sorting <code>int</code><pre><code>nums := []int{3, 7, 8, 1, 5, 4} sort.Ints(nums) fmt.Println(nums) // prints [1 3 4 5 7 8] </code></pre> </li> <li>Sorting <code>float64</code><pre><code>floats := []float64{3.2, 7.1, 7.9, 1.1, 5.2, 3.9} sort.Float64s(floats) fmt.Println(floats) // prints [1.1 3.2 3.9 5.2 7.1 7.9] </code></pre> </li> <li>Sorting <code>string</code><pre><code>strings := []string{"apple", "Banana", "cherry", "Mango", "papaya"} sort.Strings(strings) fmt.Println(strings) // [Banana Mango apple cherry papaya] </code></pre> </li> </ul> <p>Notice that <code>sort.Strings(x)</code> sort the elements in the string slice based on their Unicode value, that's why all the capital letters come first.</p> <p>That's how you can sort in ascending order using Go. Pretty easy and convenient right?</p> <p>But it's not as straightforward when we need anything other than the ascending sort, like sorting the slices in descending order for example.</p> <p>Let's look at 2 other ways of sorting to solve this problem.</p> <h2>Sort With Custom Comparator Using sort.Slice</h2> <p><code>sort.Slice()</code> sorts a slice with the provided less function. But what is a less function?</p> <blockquote> <p>Less reports whether the element with index i must sort before the element with index j.</p> </blockquote> <p>The function signature look like this:</p> <pre><code>less(i, j int) bool </code></pre> <p>Now, back to our example. We can sort the slice in decreasing order this way:</p> <pre><code>nums := []int{3, 7, 8, 1, 5, 4} sort.Slice(nums, func(i, j int) bool { return nums[i] &gt; nums[j] }) fmt.Println(nums) // prints [8 7 5 4 3 1] </code></pre> <p>At this point, you should be able to guess how the less function in <code>sort.Ints</code> is implemented. <a href="https://cs.opensource.google/go/go/+/go1.19.3:src/sort/sort.go;l=115">Check it out!</a></p> <p>If you actually visit the link, you'll notice a pattern in the built-in sorting functions.</p> <pre><code>// IntSlice attaches the methods of Interface to []int, sorting in increasing order. type IntSlice []int func (x IntSlice) Len() int { return len(x) } func (x IntSlice) Less(i, j int) bool { return x[i] &lt; x[j] } func (x IntSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] } // Float64Slice implements Interface for a []float64, sorting in increasing order, // with not-a-number (NaN) values ordered before other values. type Float64Slice []float64 func (x Float64Slice) Len() int { return len(x) } func (x Float64Slice) Less(i, j int) bool { return x[i] &lt; x[j] || (isNaN(x[i]) &amp;&amp; !isNaN(x[j])) } func (x Float64Slice) Swap(i, j int) { x[i], x[j] = x[j], x[i] } // StringSlice attaches the methods of Interface to []string, sorting in increasing order. type StringSlice []string func (x StringSlice) Len() int { return len(x) } func (x StringSlice) Less(i, j int) bool { return x[i] &lt; x[j] } func (x StringSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] } </code></pre> <p>That's because they're implementing the <code>sort.Interface</code> interface. Yes, the interface is called <code>Interface</code>.</p> <p>And that brings us to the final section, sorting using <code>sort.Sort()</code>.</p> <h2>Sorting sort.Interface Using sort.Sort()</h2> <p>This option allow the most customization and is actually the basis of how all the sorting function is the <code>sort</code> package work.</p> <p>For example, <code>sort.Ints</code> is actually:</p> <pre><code>func Ints(x []int) { Sort(IntSlice(x)) } </code></pre> <p><a href="https://cs.opensource.google/go/go/+/refs/tags/go1.19.3:src/sort/sort.go;l=157">You can also check the source code.</a></p> <p>Now, let's try to understand what the <code>sort.Sort()</code> function does.</p> <p>From the <a href="https://pkg.go.dev/sort#Sort">docs</a>:</p> <pre><code>func Sort(data Interface) </code></pre> <p><code>sort.Sort()</code> sorts data in ascending order as determined by the <code>Less</code> method. It makes one call to <code>data.Len</code> to determine n and O(n*log(n)) calls to <code>data.Less</code> and <code>data.Swap</code>. The sort is not guaranteed to be stable.</p> <p><code>data.Len</code>, <code>data.Less</code>, <code>data.Swap</code> come from the <code>sort.Interface</code> interface, which look like this:</p> <pre><code>type Interface interface { // Len is the number of elements in the collection. Len() int // Less reports whether the element with // index i should sort before the element with index j. Less(i, j int) bool // Swap swaps the elements with indexes i and j. Swap(i, j int) } </code></pre> <p>By implementing <code>sort.Interface</code>, we can also call <code>sort.Sort()</code> on our collection.</p> <p>For example, let's create a custom struct that implement the interface:</p> <pre><code>type Pet struct { name string kind string } type PetSlice []Pet func (p PetSlice) Len() int { return len(p) } func (p PetSlice) Less(i, j int) bool { return p[i].name &lt; p[j].name // sort in ascending order using the pet's name } func (p PetSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } </code></pre> <p>Then we can use our custom struct like this:</p> <pre><code>var myPets PetSlice = []Pet{ {"luna", "cat"}, {"hery", "dog"}, {"dory", "fish"}, } fmt.Println(myPets) // [{luna cat} {hery dog} {dory fish}] sort.Sort(myPets) fmt.Println(myPets) // [{dory fish} {hery dog} {luna cat}] </code></pre> <p>Everytime you call <code>sort.Sort</code> on <code>myPets</code>, <code>myPets</code> will be sorted using the <code>Less</code> method as the comparator.</p> <p>Finally, let's go back to our example about sorting int slice in decrementing order. We can also implement a custom type for that.</p> <pre><code>type myIntSlice []int func (s myIntSlice) Len() int { return len(s) } func (s myIntSlice) Less(i, j int) bool { return s[i] &gt; s[j] } func (s myIntSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } </code></pre> <p>And use it like this:</p> <pre><code>var nums myIntSlice = []int{3, 7, 8, 1, 5, 4} sort.Sort(nums) fmt.Println(nums) // [8 7 5 4 3 1] </code></pre> <p>Of course, we don't always have to declare our variable with our custom type. We can also use type casting for the situation when the data is already there.</p> <p>Anytime we need to sort an int slice in decreasing order, we can simply type cast it to our custom type.</p> <pre><code>nums := []int{3, 7, 8, 1, 5, 4} sort.Sort(myIntSlice(nums)) fmt.Println(nums) // [8 7 5 4 3 1] </code></pre> <h2>Wrap Up</h2> <p>That's it for this post. I hope it serves you well as a quick guide to the <code>sort</code> package.</p> goVincent TaneriHow To Debug TypeScript In VSCodehttps://vitaneri.com/posts/how-to-debug-typescript-in-vscode/https://vitaneri.com/posts/how-to-debug-typescript-in-vscode/How to configure VSCode's built-in debugger to debug a TypeScript Node application.Wed, 21 Sep 2022 20:22:32 GMT<p>Let's take a look at how we can configure VSCode's built-in debugger to debug a TypeScript Node application.</p> <h2>Install Dependencies</h2> <p>First, you have to install these dependencies (I prefer installing them as dev dependencies):</p> <pre><code>npm install --save-dev typescript ts-node tsconfig-paths </code></pre> <h2>Generate Source Map</h2> <p>Create a <code>tsconfig.json</code> file by running:</p> <pre><code>tsc --init </code></pre> <p>or create the file yourself.</p> <p>Then add <code>"sourceMap": true</code> to the <code>compilerOptions</code>.</p> <p>Your <code>tsconfig.json</code> file will now look something like this:</p> <pre><code>{ "compilerOptions": { "target": "ES3", "module": "commonjs", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "sourceMap": true } } </code></pre> <p>By setting the <code>sourceMap</code> property to <code>true</code>. The TypeScript compiler will now also generate a <code>.map</code> file as well as a <code>.js</code> file for each of our TypeScript files.</p> <p>Node is a JavaScript runtime. It will only execute JavaScript code. The generated <code>.map</code> file tells VSCode how to map the executing JavaScript code back to our TypeScript source.</p> <h2>Configure Debugger</h2> <p>Next, go to the debug tab, and add a JSON configuration file named <code>launch.json</code> with these contents:</p> <pre><code>{ "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "ts-debug", "skipFiles": ["&lt;node_internals&gt;/**"], "program": "${workspaceFolder}/index.ts", "runtimeArgs": ["-r", "ts-node/register", "-r", "tsconfig-paths/register"], "outFiles": ["${workspaceFolder}/**/*.js"] } ] } </code></pre> <p>Feel free to change the <code>name</code> field to anything you like.</p> <p>The most important part here is <code>runtimeArgs</code>, which contains optional arguments to be passed to the runtime executable.</p> <p>We write <code>"-r"</code> which stands for <code>require</code> to register <code>ts-node</code> and <code>tsconfig-paths</code>. <code>tsconfig-paths</code> is used to load modules whose location is specified in the paths section of <code>tsconfig.json</code>.</p> <p>Finally, make sure the <code>program</code> field points to the entry point of your app.</p> <h2>Wrap Up</h2> <p>That's it. You're done with the configuration. Now, you can put breakpoints on your code, and click on the start debugging icon or simply press the keyboard shortcut, F5, to debug.</p> typescriptvscodeVincent TaneriHow To Integrate Utterances With Astrohttps://vitaneri.com/posts/how-to-integrate-utterances-with-astro/https://vitaneri.com/posts/how-to-integrate-utterances-with-astro/A tutorial on integrating Utterances comment system with Astro.Fri, 07 Oct 2022 09:53:35 GMT<p>In this post, we're going to take a look at how I integrated Utterances with my Astro blog without any additional UI library. We'll create an Astro component that handle calling the Utterances script, and also see how we can change the theme of the Utterances' IFrame dynamically.</p> <h2>What Is Utterances</h2> <p>First, let's get to know <a href="https://utteranc.es/">Utterances</a>. Utterances is a lightweight comments widget build on GitHub issues. It's also completely free and open source. I'm using Utterances as the comment system of my blog, you can scroll down to the comments section below to see Utterances in action.</p> <blockquote> <p>You can read more about Utterances in its <a href="https://utteranc.es/">official website</a>.</p> </blockquote> <h2>Generating Utterances Script</h2> <p>Before we can put Utterances in our site, we have to generate a script to call the Utterances IFrame. You can do it by following the instructions in the <a href="https://utteranc.es/">official website</a> or the instructions below if you don't want to leave the site 😆.</p> <p>First, you have to <a href="https://github.com/apps/utterances">install Utterances in your GitHub account</a>. Give Utterances access to your site's repository and make sure that the repository is <em>public</em>.</p> <p>Next, fill in the template below with your information.</p> <pre><code>&lt;script src="https://utteranc.es/client.js" repo="[ENTER REPO HERE]" issue-term="[ISSUE TERM]" label="[LABEL NAME]" theme="[THEME NAME]" crossorigin="anonymous" async &gt;&lt;/script&gt; </code></pre> <p>Leave <code>src</code> as it is.</p> <p>The <code>repo</code> structure is: <code>owner/repo</code>. For example: <code>repo=tanerijun/vitaneri-v3</code>.</p> <p>For <code>issue-term</code>, you can choose among: <code>pathname</code>, <code>url</code>, <code>title</code>, <code>og:title</code>, <code>[ISSUE NUMBER]</code>, <code>[SPECIFIC TERM]</code>.</p> <p>Fill <code>label</code> with the label that'll be assigned to issues created by Utterances. <code>label</code> is optional. If you don't need it, just remove the <code>label</code> attribute from the <code>script</code> tag. But if you do need it, make sure that the label exist in your repo. To create your own issue label, you can read the instructions <a href="https://docs.github.com/en/issues/using-labels-and-milestones-to-track-work/managing-labels#creating-a-label">here</a>.</p> <p>As for <code>theme</code>, you can choose among these options: <code>github-light</code>, <code>github-dark</code>, <code>preferred-color-scheme</code>, <code>github-dark-orange</code>, <code>icy-dark</code>, <code>dark-blue</code>, <code>photon-dark</code>, <code>boxy-light</code>, <code>gruvbox-dark</code>.</p> <p>The next step is to call that script from your Astro app.</p> <h2>Creating Utterances Astro component</h2> <p>Let's create a component that can call that Utterances script for reusability. Start by creating an Astro component. I named mine <code>Utterances.astro</code>.</p> <p>Next, put a single <code>div</code> element in the component with whatever <code>id</code> you like. It's going to serve as a container for Utterances.</p> <pre><code>&lt;div id="utterances-container"&gt;&lt;/div&gt; </code></pre> <p>To send the script to the client, we have to write our JavaScript in a <code>&lt;script&gt;</code> tag, not frontmatter(<code>---</code>). Inside the <code>&lt;script&gt;</code> tag, let's put in these code:</p> <pre><code>const script = document.createElement("script"); const container = document.querySelector("#utterances-container"); // your id in your html above // Replace the value of each key with yours Object.entries({ src: "https://utteranc.es/client.js", repo: "tanerijun/vitaneri-v3", "issue-term": "pathname", label: "post comments", // omit this line, if you don't need label theme: "github-dark", crossorigin: "anonymous", }).forEach(([key, value]) =&gt; { script.setAttribute(key, value); }); container?.appendChild(script); </code></pre> <p>So basically, we're creating a <code>script</code> element, then we assign it all our Utterances` script attributes, and finally, we insert the script into the container.</p> <p>Your <code>Utterances.astro</code> should now look something like this:</p> <pre><code>&lt;div id="utterances-container"&gt;&lt;/div&gt; &lt;script&gt; const script = document.createElement("script"); const container = document.querySelector("#utterances-container"); Object.entries({ src: "https://utteranc.es/client.js", repo: "tanerijun/vitaneri-v3", "issue-term": "pathname", label: "post comments", theme: "github-dark", crossorigin: "anonymous", }).forEach(([key, value]) =&gt; { script.setAttribute(key, value); }); container?.appendChild(script); &lt;/script&gt; </code></pre> <p>With that, we're finished with the component. You can plug it wherever you want your Utterances comment to show up.</p> <h2>Changing Utterances Theme Based On Site Theme</h2> <p>Now let's take this a step further by having the Utterances theme match the site theme. This part really depends on how the theming system on your site works. A common approach is to persist theming information in local storage. I'm going to use that as an example here.</p> <pre><code>&lt;div id="utterances-container"&gt;&lt;/div&gt; &lt;script&gt; const script = document.createElement("script"); const container = document.querySelector("#utterances-container"); const currentTheme = localStorage.getItem("theme"); // Set configurations Object.entries({ src: "https://utteranc.es/client.js", repo: "tanerijun/vitaneri-v3", "issue-term": "pathname", label: "post comments", theme: currentTheme == "light" ? "github-light" : "github-dark", crossorigin: "anonymous", }).forEach(([key, value]) =&gt; { script.setAttribute(key, value); }); container?.appendChild(script); &lt;/script&gt; </code></pre> <p>Nice our Utterances theme change dynamically now. But it's still not perfect.</p> <p>Usually, a site that support both light mode and dark mode will have a button to toggle between the modes. With our current implementation, the theme only change when our component mounts. In other words, even if we click on the button to toggle site theme change, we have to refresh the page before Utterance know about the change.</p> <h2>Synchronizing Utterances Theme With Site Theme</h2> <p>In order to make sure the Utterance theme is synced with the <code>theme</code> value in our local storage, we are going to create a function to trigger theme change manually and bind it to our light/dark mode toggle button.</p> <pre><code>function toggleUtterancesTheme() { if (document.querySelector(".utterances-frame")) { const theme = localStorage.getItem("theme") === "light" ? "github-light" : "github-dark"; const message = { type: "set-theme", theme, }; const iframe = document.querySelector(".utterances-frame") as HTMLIFrameElement; // omit as HTMLIFrameElement if you're wring JS iframe?.contentWindow?.postMessage(message, "https://utteranc.es"); } } </code></pre> <p>The function read our new <code>theme</code> value and send a message containing the new <code>theme</code> value to the Utterance IFrame. This way we can change the Utterance theme without refreshing the page.</p> <p>And finally, we need to make sure our light/dark mode toggle button change the value in local storage and call the function.</p> <pre><code>themeBtn?.addEventListener("click", function () { // toggle light/dark mode if (htmlClassList?.contains("theme-dark")) { localStorage.setItem("theme", "light"); } else { localStorage.setItem("theme", "dark"); } toggleUtterancesTheme(); }); </code></pre> <p>With that, our Utterances theme will be in sync with our local storage 🎉.</p> <h2>Wrap up</h2> <p>That's it for this post. We've successfully integrate Utterances with our Astro site. You might need to adjust the theme codes with how your theme system is implemented, but you should have a general idea of how to do it now. If you have any questions, feel free to comment below.</p> astrogeneralVincent TaneriHow To Remove The "Clear All" Button From Search Inputhttps://vitaneri.com/posts/how-to-remove-the-clear-all-button-from-search-input/https://vitaneri.com/posts/how-to-remove-the-clear-all-button-from-search-input/A guide on how to remove the clear all button when you set input type to search in HTML.Tue, 18 Jul 2023 12:04:38 GMT<p>When you create a search input, <code>&lt;input type="search" /&gt;</code>, in HTML. It's going to display a clear all button, usually shaped as a cross ("X"), at the end of the input.</p> <p>I am talking about this:</p> <p></p> <p>We can remove the "X" with these CSS:</p> <pre><code>/* clears the 'X' in searchbar from Internet Explorer */ input[type="search"]::-ms-clear { display: none; width: 0; height: 0; } input[type="search"]::-ms-reveal { display: none; width: 0; height: 0; } /* clears the 'X' in searchbar from Chrome */ input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-results-button, input[type="search"]::-webkit-search-results-decoration { display: none; } </code></pre> <p>That's it! Have a good day 😊.</p> cssVincent TaneriImplementing Map, Filter, And Reduce Using Generic In Gohttps://vitaneri.com/posts/implementing-map-filter-and-reduce-using-generic-in-go/https://vitaneri.com/posts/implementing-map-filter-and-reduce-using-generic-in-go/An implementation of map, filter, and reduce using Go's generic.Tue, 15 Nov 2022 08:25:07 GMT<p>This is a short post showing an implementation of map, filter, and reduce using generic in Go.</p> <h2>Map</h2> <p>Map creates a new slice and populates it with the results of calling the provided function on every element in input slice.</p> <pre><code>func Map[T1, T2 any](s []T1, f func(T1) T2) []T2 { r := make([]T2, len(s)) for i, v := range s { r[i] = f(v) } return r } </code></pre> <p>Usage example:</p> <pre><code>nums := []int{1, 2, 3, 4, 5} numsDoubled := Map(nums, func(n int) int { return n * 2 }) fmt.Println(numsDoubled) // prints [2 4 6 8 10] </code></pre> <h2>Filter</h2> <p>Filter returns a new slice that contains elements from the input slice which return <code>true</code> when they're passed as a parameter to the provided testing function.</p> <pre><code>func Filter[T any](s []T, f func(T) bool) []T { var r []T for _, v := range s { if f(v) { r = append(r, v) } } return r } </code></pre> <p>Usage example:</p> <pre><code>nums := []int{1, 2, 3, 4, 5} evenNums := Filter(nums, func(n int) bool { return n%2 == 0 }) fmt.Println(evenNums) // prints [2 4] </code></pre> <h2>Reduce</h2> <p>Reduce runs a reducer function (the provided function) over all elements in the array, in ascending-index order, and accumulates them into a single value.</p> <p>Every time, the return value of the reducer function is passed again to the next invocation of the function as the accumulator. Reduce returns the final value of the accumulator.</p> <pre><code>func Reduce[T1, T2 any](s []T1, accumulator T2, f func(T2, T1) T2) T2 { r := accumulator for _, v := range s { r = f(r, v) } return r } </code></pre> <p>Usage example:</p> <pre><code>nums := []int{1, 2, 3, 4, 5} sumOfNums := Reduce(nums, 0, func(acc, n int) int { return acc + n }) fmt.Println(sumOfNums) // prints 15 </code></pre> <h2>Wrap Up</h2> <p>That's how we can implement map, filter, and reduce in Go. We can use these function just like how we use them in Python, JavaScript, Dart, Java, etc.</p> goVincent TaneriIntroduction To Generics In TypeScripthttps://vitaneri.com/posts/introduction-to-generics-in-typescript/https://vitaneri.com/posts/introduction-to-generics-in-typescript/A quick introduction to TypeScript's generics.Sat, 29 Oct 2022 01:58:28 GMT<p>This post is a simple introduction to generics in TypeScript.</p> <h2>What Is Generics?</h2> <p>Generics is a way of writing code that will work with a wide range of objects and primitives. It's really useful when we want to write codes that will work with any sort of type, interface, or class definition.</p> <p>For example, a function to find an element in a list where the elements can be strings, numbers, or any other type. Or maybe you have a Queue class that need to work with any type of primitive. These scenarios are when we need to use generics.</p> <h2>Basic Syntax</h2> <p>Let's first look at a code snippet that uses generics.</p> <pre><code>function print&lt;T&gt;(val: T) { console.log(`typeof T is: ${typeof val}`); console.log(`value is: ${val}`); } </code></pre> <p>Here, we have a function called <code>print</code> that is using generics. The function take an argument called <code>val</code> of type <code>T</code>.</p> <p><strong>Note</strong> that the <code>T</code> is only a convention. You can name it whatever you want.</p> <p>Let's see how it works when we call the function with arguments of different type.</p> <pre><code>print&lt;number&gt;(1); print&lt;string&gt;("hello"); print&lt;boolean&gt;(true); print&lt;function&gt;(() =&gt; {}); print&lt;object&gt;({ name: "John" }); </code></pre> <p>And the output:</p> <pre><code>typeof T is: number value is: 1 typeof T is: string value is: hello typeof T is: boolean value is: true typeof T is: function value is: function () {} typeof T is: object value is: [object Object] </code></pre> <p>As you can see, the function works with every type. All we have to do is specify a type inside the angle brackets, then all <code>T</code> inside the function will be replaced with that type.</p> <p>Take <code>print&lt;number&gt;()</code> for example. All <code>T</code> that appear inside the function will be replaced with <code>number</code>.</p> <pre><code>function print(val: number) { console.log(`typeof T is: ${typeof val}`); console.log(`value is: ${val}`); } </code></pre> <p>And if we give an argument that's not a number, we'll get an error.</p> <p>For example, if we run <code>print&lt;number&gt;("hello")</code>. We'll get the following error.</p> <pre><code>Argument of type 'string' is not assignable to parameter of type 'number'. </code></pre> <p>Typescript prevents us from calling a generic function with the wrong type as an argument.</p> <p><strong>Note</strong> that we don't need to explicitly specify the type the function takes. It can be inferred. For example the code below will still work as expected.</p> <pre><code>print(1); print("hello"); print(true); print(() =&gt; {}); print({ name: "John" }); </code></pre> <h2>Multiple Generics</h2> <p>We are not limited to one generic in TypeScript. We can use as many as we needs.</p> <p>For example:</p> <pre><code>function twoTypes&lt;A, B&gt;(arg1: A, arg2: B) { console.log(`Type of the first argument is: ${typeof arg1}`); console.log(`Type of the second argument is: ${typeof arg2}`); } </code></pre> <p>Here, we have a function that take 2 generic types. Let's see how it works using the code below.</p> <pre><code>twoTypes&lt;number, string&gt;(1, "hello"); twoTypes(2, "world"); twoTypes("hello", "world"); </code></pre> <p>Notice that the 2 generics can also be of the same type as shown at line 3.</p> <pre><code>Type of the first argument is: number Type of the second argument is: string Type of the first argument is: number Type of the second argument is: string Type of the first argument is: string Type of the second argument is: string </code></pre> <h2>Type Constraint</h2> <p>You can see how powerful generics is from the examples above. Our generic function now works with any type. But usually, we want to only allow a specific set of types to be used within our generic. We can accomplish this by constraining the type using the <code>extends</code> keyword.</p> <p>For example:</p> <pre><code>function takeArray&lt;T extends Array&lt;string&gt; | Array&lt;number&gt;&gt;(items: T) {} </code></pre> <p>Now we are constraining the <code>T</code> on the function above to either <code>Array&lt;string&gt;</code> or <code>Array&lt;number&gt;</code>. This means that whatever <code>T</code> is used within our code, it can only be interpreted as either an array of string or an array of number.</p> <p>If we try to call the function with array of boolean, <code>takeArray([true, false])</code>, we'll get the following error.</p> <pre><code>Type 'boolean' is not assignable to type 'string | number'. </code></pre> <p><strong>Note</strong> that <code>Array&lt;T&gt;</code> is a predefined type from the standard TypeScript <a href="https://github.com/microsoft/TypeScript/blob/main/lib/lib.es5.d.ts">type definitions</a>.</p> <h2>Generic Constraints</h2> <p>We can also construct a generic type from another generic type.</p> <p>For example:</p> <pre><code>function printProperty&lt;T, K extends keyof T&gt;(obj: T, key: K) { console.log(`obj[${key}] = ${obj[key]}`); } </code></pre> <p>Here, our function take two generic types, <code>T</code> and <code>K</code>. The type <code>K</code> is constrained to be the value computed from the <code>keyof</code> operator on type <code>T</code>.</p> <p>The <code>keyof</code> operator will return a string literal type of the object's properties. Therefore <code>K</code> will be constrained to the property names of the type <code>T</code>.</p> <p>Let's look at an example.</p> <pre><code>const obj = { id: 1, name: "John", }; printProperty(obj, "id"); printProperty(obj, "name"); printProperty(obj, "age"); </code></pre> <p>The first and second line of the code will produce the following output as expected:</p> <pre><code>obj[id] = 1 obj[name] = John </code></pre> <p>But the third line will result in an error because the property <code>age</code> doesn't exist on type <code>keyof T</code> which is extended by type <code>K</code>.</p> <pre><code>Argument of type '"age"' is not assignable to parameter of type '"id" | "name"'. </code></pre> <h2>Creating A New Object Within Generics</h2> <p>There might be a time when we need to create a factory function that return an instance of a class.</p> <p>For example:</p> <pre><code>class Fish {} function createClassInstance&lt;T&gt;(arg: T): T { return new arg(); } let instanceOfFish = createClassInstance(Fish); </code></pre> <p>Surprisingly, the code above results in the following error.</p> <pre><code>This expression is not constructable. Type 'unknown' has no construct signatures. </code></pre> <p>This is happening because the name of <code>T</code> only exists at compile time. We can use <code>T</code> for type checking but not for constructing an object of type <code>T</code> unless we have access to the constructor.</p> <p>In order to fix the code above, we need to refer to type <code>T</code> by its constructor function.</p> <pre><code>class Fish {} function createClassInstance&lt;T&gt;(arg: { new (): T }): T { return new arg(); } let instanceOfFish = createClassInstance(Fish); </code></pre> <p>With this change, our code will now compile and work as expected.</p> <h2>Wrap Up</h2> <p>That's it for the introduction to generics in TypeScript 🎉.</p> <p>Having a good understanding of generics is really important to use the more advanced TypeScript features like <a href="understanding-mapped-types-in-typescript">Mapped Types</a>), Conditional Types, etc.</p> typescriptVincent TaneriIntroduction to Java's Stream APIhttps://vitaneri.com/posts/introduction-to-javas-stream-api/https://vitaneri.com/posts/introduction-to-javas-stream-api/Learn Java's Stream API by working with a sample data.Thu, 08 Sep 2022 01:15:32 GMT<p>In this post, we'll learn Java's Stream API by working with a sample data source using the Stream API. By the end of this article, you'll have a basic understanding of the Stream API in Java and what kind of problem it solves.</p> <h2>Overview</h2> <p>Let's start with the question "What is a stream?".</p> <p>Stream is basically just a wrapper for a data source that allows you to work with the data declaratively. By using stream, we can process data much faster than when working with it imperatively. Stream makes working with <em>collection</em> much more fun and easier.</p> <p>First, let's take a look at the data source that we'll be using in our examples. Then we'll compare how to work with the data source using both imperative and declarative methods so that you can see the advantage of using the stream API. After that, we'll take a look at some common operations using stream by answering some questions about the data source, and letting the stream API answer it for us.</p> <blockquote> <p>Note: I assume that you know the basic working knowledge of Lambda Expressions, Method Reference, and Optional</p> </blockquote> <h2>Introducing Our Data Source</h2> <p>First, let's look at the data source we'll be working with throughout the article. We'll be working with a list of <code>Cat</code> called <code>cats</code>.</p> <p>Let's first look at how <code>Cat</code> is implemented:</p> <pre><code>public class Cat { private String name; private int age; private String gender; public Cat(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "Cat{" + "name='" + name + '\'' + ", age=" + age + ", gender='" + gender + '\'' + '}'; } } </code></pre> <p><code>Cat</code> is a very simple object with 3 fields: name, age, and gender. We've also added getters and setters for each field and a <code>toString()</code> method that's going to be useful for displaying the result of our operations later.</p> <p>Next, let's look at the <code>Main</code> class. This is where we'll be working throughout the article.</p> <pre><code>public class Main { public static void main(String[] args) { List&lt;Cat&gt; cats = List.of( new Cat("Bob", 5, "M"), new Cat("Coco", 7, "F"), new Cat("Amelia", 3, "F"), new Cat("Dan", 2, "M") ); } } </code></pre> <p>For now, it only contains a list of <code>Cat</code> called <code>cats</code>.</p> <h2>Working With Data Imperatively</h2> <p>Now, what if I want to create a new list that only contains female cats?</p> <p>The standard way of doing this, the imperative way, is like this:</p> <pre><code>List&lt;Cat&gt; femaleCats = new ArrayList&lt;&gt;(); for (Cat cat: cats) { if ("F".equals(cat.getGender())) { femaleCats.add(cat); } } </code></pre> <p>We just did all these steps:</p> <ol> <li>Create a new empty list.</li> <li>Loop through the <code>cats</code> list.</li> <li>In the loop, we check if the cat's gender is female (F).</li> <li>If it is, we add the cat to the new list we created.</li> </ol> <p>This is what it looks like if we print <code>femaleCats</code>.</p> <pre><code>Cat{name='Coco', age=7, gender='F'} Cat{name='Amelia', age=3, gender='F'} </code></pre> <h2>Working With Data Declaratively</h2> <p>And now we'll demonstrate how to work with the data declaratively using the stream API. Working declaratively means that we simply ask the program what we want without the need of specifying each step in detail just like what we did when working imperatively.</p> <p>This is how we can do the same thing as we did above with the stream API.</p> <pre><code>List&lt;Cat&gt; femaleCats = cats .stream() .filter(cat -&gt; "F".equals(cat.getGender())) .collect(Collectors.toList()); </code></pre> <p>So we start off by calling the <code>.stream()</code> method on the collection (<code>cats</code>), which returns a <code>Stream</code> with the collection as its source. Now we can start working using the stream API. We simply have to ask what we want from the collection.</p> <p>In this case, we want to filter out the list. We want a new list that only contains female cats. We do it by chaining <code>.filter()</code> method. <code>.filter()</code> takes a <code>Predicate</code>, which is basically just a functional interface that returns a boolean. In our case, we need to pass in <code>cat -&gt; "F".equals(cat.getGender))</code>.</p> <p>The last step is to convert the result of <code>.filter()</code> into a <code>List</code> because <code>.filter()</code> returns a Stream. This is by design, and it's really useful. We can chain the result of our <code>.filter()</code> with other methods on the stream API which you will see later.</p> <p>Now to convert it into a <code>List</code> we have to call the method <code>.collect()</code>. <code>.collect()</code> take a <code>Collector</code> as parameter. Since we want our end result to be a <code>List</code>, the <code>Collector</code> we need to pass in is <code>Collectors.toList()</code>.</p> <p>Finally, we get the same result if we print <code>femaleCats</code>.</p> <pre><code>Cat{name='Coco', age=7, gender='F'} Cat{name='Amelia', age=3, gender='F'} </code></pre> <p>Do you see the advantage of the declarative approach now? What used to be several lines of code in the imperative mode is now only a line, and the code is much more readable.</p> <p>The advantage might not be too obvious now as the example was really simple, but it'll become clear how useful it is when we try to do multiple operations by chaining stream methods later in this article.</p> <h2>Common Operation Using Stream API</h2> <p>Now, let's take a look at some common operations using the stream API.</p> <h3>forEach</h3> <p><code>.forEach()</code> simply loop over each element in the stream and apply the function you provide to each element.</p> <p>For example, the code below prints the name of each cat.</p> <pre><code>cats.stream().forEach(cat -&gt; System.out.println(cat.getName())); </code></pre> <p>Note that <code>.forEach()</code> doesn't return a Stream. So you won't be able to chain another method after calling it. This kind of method is also called a terminal method.</p> <h3>map</h3> <p><code>.map()</code> does the same thing <code>forEach()</code> does. That is, applying a function to each element in a Stream. The difference is that <code>.map()</code> returns a new Stream, which can be another data type.</p> <p>Let's look at an example of using <code>.map()</code>.</p> <p>Say, We want to change the gender format of our cat from "M" and "F" to "Male" and "Female" respectively. We can use <code>.map()</code> to solve this problem.</p> <pre><code>List&lt;Cat&gt; newCats = cats .stream() .map(cat -&gt; new Cat( cat.getName(), cat.getAge(), "F".equals(cat.getGender()) ? "Female" : "Male")) .collect(Collectors.toList()); </code></pre> <p>And if we print the <code>newCats</code>, we get what we want.</p> <pre><code>Cat{name='Bob', age=5, gender='Male'} Cat{name='Coco', age=7, gender='Female'} Cat{name='Amelia', age=3, gender='Female'} Cat{name='Dan', age=2, gender='Male'} </code></pre> <h3>filter</h3> <p>We already looked at how <code>.filter()</code> works before. It returns a new Stream that contains the element from the original Stream that fulfills a condition.</p> <p>Let's look at another example. Say that we want a new List of cats that are younger than 5.</p> <pre><code>List&lt;Cat&gt; catYoungerThanFive = cats .stream() .filter(cat -&gt; cat.getAge() &lt; 5) .collect(Collectors.toList()); </code></pre> <p>And this is the result of printing <code>catYoungerThanFive</code>.</p> <pre><code>Cat{name='Amelia', age=3, gender='F'} Cat{name='Dan', age=2, gender='M'} </code></pre> <h3>sorted</h3> <p>We can also sort the list using the <code>.sorted()</code> method. The method takes in a <code>Comparator</code> as a parameter.</p> <p>For example, if we want to sort the cats by their age.</p> <pre><code>List&lt;Cat&gt; newCats = cats .stream() .sorted(Comparator.comparing(Cat::getAge)) .collect(Collectors.toList()); </code></pre> <p>And this is the result:</p> <pre><code>Cat{name='Dan', age=2, gender='M'} Cat{name='Amelia', age=3, gender='F'} Cat{name='Bob', age=5, gender='M'} Cat{name='Coco', age=7, gender='F'} </code></pre> <p>You can also reverse it by adding the <code>.reversed()</code> method like this:</p> <pre><code>List&lt;Cat&gt; newCats = cats .stream() .sorted(Comparator.comparing(Cat::getAge).reversed()) .collect(Collectors.toList()); </code></pre> <p>And this is the result:</p> <pre><code>Cat{name='Coco', age=7, gender='F'} Cat{name='Bob', age=5, gender='M'} Cat{name='Amelia', age=3, gender='F'} Cat{name='Dan', age=2, gender='M'} </code></pre> <h3>min and max</h3> <p><code>.min()</code> and <code>.max()</code> are used to get the minimum and maximum values in a stream. To use the methods, we have to pass in a Comparator.</p> <p>Note that the <code>.min()</code> and <code>.max()</code> methods return an Optional because there might not be a result. So you've got to handle that.</p> <p>Say that we want to find the youngest and the oldest cat from our list. We can that using <code>.min()</code> and <code>.max()</code> like this:</p> <pre><code>Optional&lt;Cat&gt; youngestCat = cats .stream() .min(Comparator.comparing(Cat::getAge)); System.out.println( "Youngest cat: " + youngestCat.orElseThrow(CatNotFoundException::new) ); Optional&lt;Cat&gt; oldestCat = cats .stream() .max(Comparator.comparing(Cat::getAge)); System.out.println( "Oldest cat: " + oldestCat.orElseThrow(CatNotFoundException::new) ); </code></pre> <p>And this is the result:</p> <pre><code>Youngest cat: Cat{name='Dan', age=2, gender='M'} Oldest cat: Cat{name='Coco', age=7, gender='F'} </code></pre> <h3>allMatch, anyMatch, and noneMatch</h3> <p>These operations take a Predicate as a parameter just like <code>.filter()</code> and return a boolean.</p> <p><code>.allMatch()</code> returns true only if all elements in the stream match the Predicate.</p> <pre><code>boolean allOlderThanFive = cats .stream() .allMatch(cat -&gt; cat.getAge() &gt; 5); System.out.println("allOlderThanFive = " + allOlderThanFive); // returns false </code></pre> <p><code>.anyMatch()</code> returns true if any one of the elements in the stream matches the Predicate.</p> <pre><code>boolean anyOlderThanFive = cats .stream() .anyMatch(cat -&gt; cat.getAge() &gt; 5); System.out.println("anyOlderThanFive = " + anyOlderThanFive); // returns true </code></pre> <p><code>.noneMatch()</code> returns true if none of the elements match the Predicate.</p> <pre><code>boolean noneOlderThanFive = cats .stream() .noneMatch(cat -&gt; cat.getAge() &gt; 5); System.out.println("noneOlderThanFive = " + noneOlderThanFive); // returns false </code></pre> <h3>collect</h3> <p><code>collect</code> is a terminal operation that we've been using several times in the examples above. It's the most common way to end a stream and package the elements in the stream into a collection.</p> <p>Of course, we're not limited to collect into a list like what we did in the examples above. We can collect into any collection we want: map, set, etc.</p> <p>Let's look at an example of collecting into a map.</p> <p>Say that I want to group my cats based on their gender. We can do it like this:</p> <pre><code>Map&lt;String, List&lt;Cat&gt;&gt; catMap = cats .stream() .collect(Collectors.groupingBy(Cat::getGender)); </code></pre> <p>Now, if we print the map like this:</p> <pre><code>catMap.forEach((gender, catsList) -&gt; { System.out.println(gender + " cat: "); catsList.forEach(System.out::println); }); </code></pre> <p>We'll get this in the console:</p> <pre><code>F cat: Cat{name='Coco', age=7, gender='F'} Cat{name='Amelia', age=3, gender='F'} M cat: Cat{name='Bob', age=5, gender='M'} Cat{name='Dan', age=2, gender='M'} </code></pre> <h2>Chaining Stream Methods</h2> <p>You can also chain multiple stream methods together. Which we have been doing all along in the examples above. But let's look at it again using another example.</p> <p>Say that I want to create a new List that only contains the name of male cats that are older than 4. We can do it like this:</p> <pre><code>List&lt;String&gt; newCats = cats .stream() .filter(cat -&gt; "M".equals(cat.getGender())) .filter(cat -&gt; cat.getAge() &gt; 4) .map(Cat::getName) .collect(Collectors.toList()); newCats.forEach(System.out::println); // Bob </code></pre> <h2>Wrap Up</h2> <p>That's it for this article. I hope you've got a better understanding of the stream API now. I also hope that you can see how useful and powerful the stream API is, how it allows us to simply ask questions about our collection instead of implementing each step individually using the imperative approach.</p> javaVincent TaneriIntroduction To Transaction In Springhttps://vitaneri.com/posts/introduction-to-transaction-in-spring/https://vitaneri.com/posts/introduction-to-transaction-in-spring/Explaining Transaction in Spring (The ELI5 way).Sat, 03 Sep 2022 03:22:27 GMT<p>In this post, we'll implement a simple Spring app to understand transaction. By the end of this post, you'll be equipped with the basic knowledge to work with transaction in Spring.</p> <p>Let's start the tutorial by introducing the concept of transaction. What exactly is a transaction?</p> <h2>What Is A Transaction</h2> <p>A transaction is a sequence of operations that are either executed successfully together or not at all. In the real-world scenario, transaction is often used to avoid data inconsistencies.</p> <p>If any operations in the transaction were to fail, the transaction <em>rolls back</em>. In other words, the app is restored to how it was before the transaction happened.</p> <p>If all the operations are executed successfully, all the changes that happened as a result of the transaction will be finalized. We often say that the transaction <em>commits</em> in this case.</p> <p>Let's look at a simple example of how transaction can be useful. Suppose you have a banking app, and it has the functionality of transferring money. The functionality implements these 2 steps:</p> <ol> <li>Withdraw money from the sender's account.</li> <li>Deposit the money to the receiver's account.</li> </ol> <p>Imagine if the transaction at step 2 failed for some reason. What happened to the sender's money?</p> <p>This is where transaction comes into play. In this case, the transaction will roll back the app to how it was before step 1 is executed. The sender's money will not be withdrawn. No harm done.</p> <h2>Using Transaction In Spring</h2> <p>To implement transaction in Spring, all you have to do is to put the <code>@Transactional</code> annotation before a class or a method. If you put the method on a class, you tell Spring that every method in the class has to be transactional.</p> <blockquote> <p>Note: If you are not using Spring Boot, you'll have to add the <code>@EnableTransactionManagement</code> on your project's configuration class.</p> </blockquote> <p>Behind the scene, Spring will configure an <em>aspect</em> that intercepts all the methods annotated with <code>@Transactional</code>. The <em>aspect</em> manages the transaction. If the transaction throws an exception, the changes will be rolled back, otherwise, they will be committed.</p> <h2>Implementing An Example App</h2> <p>To clear things up, We'll create a simple app that mimics the scenario from the example above. Feel free to follow along or download the source code <a>here</a>.</p> <blockquote> <p>Note: I assume that you know the basics of Spring Boot and how to interact with a database using JDBCTemplate, which you can find more <a href="https://blog.vitaneri.com/spring-boot-working-with-database-using-jdbctemplate">here</a>.</p> </blockquote> <h3>Generating App With Spring Initializr</h3> <p>First, use <a href="https://start.spring.io/">Spring Initializr</a> to generate a Spring Boot project using these dependencies.</p> <pre><code>&lt;dependencies&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-jdbc&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;com.h2database&lt;/groupId&gt; &lt;artifactId&gt;h2&lt;/artifactId&gt; &lt;scope&gt;runtime&lt;/scope&gt; &lt;/dependency&gt; &lt;/dependencies&gt; </code></pre> <p>For simplicity's sake, we will use <a href="https://www.h2database.com/">H2 memory database</a>, and use JDBCTemplate to interact with it.</p> <h3>Configuring H2 Database</h3> <p>We'll keep the database simple. The database will contain a table called <code>account</code> with 3 columns: id, name, and money.</p> <p>Therefore, our <code>schema.sql</code> in /src/main/resources/ will look like this:</p> <pre><code>CREATE TABLE account ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, money DOUBLE NOT NULL ); </code></pre> <p>We then fill in 2 users in our table. A sender and a receiver, each with $100 in their account. We put these queries inside <code>data.sql</code> in /src/main/resources/.</p> <pre><code>INSERT INTO account (name, money) VALUES ('John Doe', 100); INSERT INTO account (name, money) VALUES ('Jane Doe', 100); </code></pre> <blockquote> <p>Note: Spring Boot will automatically execute these 2 files when we start our app.</p> </blockquote> <h3>Create Model Object</h3> <p><em>From this session onwards, we'll be working in the /src/main/java folder.</em></p> <p>Next, let's create an object that models our table's row.</p> <pre><code>package com.example.model; public class Account { private int id; private String name; private double money; // Getters and setters } </code></pre> <h3>Create Repository Object</h3> <p>Next, we'll create a repository object that'll be responsible for interacting with the database.</p> <pre><code>package com.example.repository; @Repository public class AccountRepository { private final JdbcTemplate jdbc; public AccountRepository(JdbcTemplate jdbc) { this.jdbc = jdbc; } public void changeMoneyAmount(long id, double amount) { String sql = "UPDATE account SET money = ? WHERE id = ?"; jdbc.update(sql, amount, id); } public Account findAccountById(long id) { String sql = "SELECT * FROM account WHERE id = ?"; return jdbc.queryForObject(sql, new AccountRowMapper(), id); } public List&lt;Account&gt; findAllAccounts() { String sql = "SELECT * FROM account"; return jdbc.query(sql, new AccountRowMapper()); } } </code></pre> <p>This is the implementation for the <code>AccountRowMapper</code> that we need to pass to <code>jdbc.query</code> to map the result of our query into a format that our application knows how to work with.</p> <pre><code>package com.example.repository.mappers; public class AccountRowMapper implements RowMapper&lt;Account&gt; { @Override public Account mapRow(ResultSet resultSet, int i) throws SQLException { Account a = new Account(); a.setId(resultSet.getInt("id")); a.setName(resultSet.getString("name")); a.setMoney(resultSet.getDouble("money")); return a; } } </code></pre> <h3>Create Service Object</h3> <p>Since this service object contains logic that enables our app to transfer money, we'll name it <code>TransferService</code>. The class will receive an instance of <code>AccountRepository</code> from the Spring context to interact with our database. And the logic will be inside the <code>transferMoney()</code> method annotated with <code>@Transactional</code>.</p> <pre><code>package com.example.service; @Service public class TransferService { private final AccountRepository accountRepository; public TransferService(AccountRepository accountRepository) { this.accountRepository = accountRepository; } @Transactional public void transferMoney(long senderId, long receiverId, double amount) { Account sender = accountRepository.findAccountById(senderId); Account receiver = accountRepository.findAccountById(receiverId); double senderNewMoney = sender.getMoney() - amount; double receiverNewMoney = receiver.getMoney() + amount; accountRepository.changeMoneyAmount(senderId, senderNewMoney); accountRepository.changeMoneyAmount(receiverId, receiverNewMoney); } public List&lt;Account&gt; getAllAccounts() { return accountRepository.findAllAccounts(); } } </code></pre> <h3>Create Controller Class</h3> <p>Now that we have implemented our logic for transferring money, the final step is to expose it with a Controller. Below is the code for our Controller class.</p> <pre><code>package com.example.controller; @RestController public class AccountController { private final TransferService transferService; public AccountController(TransferService transferService) { this.transferService = transferService; } @PostMapping("/transfer") public void transferMoney(@RequestBody TransferRequest request) { transferService.transferMoney(request.getSenderId(), request.getReceiverId(), request.getAmount()); } @GetMapping("/accounts") public List&lt;Account&gt; getAllAccounts() { return transferService.getAllAccounts(); } } </code></pre> <p>We also need a data transfer object called <code>TransferRequest</code> that models our HTTP request body.</p> <pre><code>package com.example.dto; public class TransferRequest { private long senderId; private long receiverId; private double amount; // Getters and setters } </code></pre> <h3>Running Our App</h3> <p>We're now done implementing our app. Let's run the app and try calling its endpoints with an API testing tool (Postman, cURL, etc.).</p> <p>This is what I did:</p> <ol> <li>Send a POST request to the <code>/transfer</code> route, with the request body below.</li> </ol> <pre><code>{ "senderId": 1, "receiverId": 2, "amount": 20 } </code></pre> <ol> <li>Send a GET request to the <code>/accounts</code> route, and get back the following JSON.</li> </ol> <pre><code>[ { "id": 1, "name": "John Doe", "money": 80.0 }, { "id": 2, "name": "Jane Doe", "money": 120.0 } ] </code></pre> <p>Seems like our app is working as expected. But how do we know if the <code>@Transactional</code> annotation really works? We are going to prove that in the next section.</p> <h3>Testing The <code>@Transaction</code> Annotation</h3> <p>To test if the <code>@Transaction</code> annotation really works, let's throw a <code>RuntimeException</code> in our <code>transferMoney()</code> method.</p> <pre><code>@Transactional public void transferMoney(long senderId, long receiverId, double amount) { Account sender = accountRepository.findAccountById(senderId); Account receiver = accountRepository.findAccountById(receiverId); double senderNewMoney = sender.getAmount().subtract(amount); double receiverNewMoney = receiver.getAmount().add(amount); accountRepository.changeMoneyAmount(senderId, senderNewAmount); accountRepository.changeMoneyAmount(receiverId, receiverNewAmount); throw new RuntimeException("Problem executing transaction."); } </code></pre> <p>Now let's restart the app and call the endpoints again.</p> <ol> <li>Send a POST request to the <code>/transfer</code> route, with the request body below.</li> </ol> <pre><code>{ "senderId": 1, "receiverId": 2, "amount": 20 } </code></pre> <ol> <li>Send a GET request to the <code>/accounts</code> route. And unsurprisingly, the result is different from our first application run. The <code>@Transactional</code> annotation did work as expected.</li> </ol> <pre><code>[ { "id": 1, "name": "John Doe", "money": 100.0 }, { "id": 2, "name": "Jane Doe", "money": 100.0 } ] </code></pre> <p>Because there's an error, the transaction rollback our application. That's why there's no change at all. The app is just like it was before we execute the <code>transferMoney()</code> method.</p> <p>And if you check the log, you'll find <code>java.lang.RuntimeException: Problem executing transaction.</code> printed there.</p> <p>Before we end the tutorial, let me introduce you to a common pitfall: <em>Handling exceptions inside the method instead of throwing them.</em></p> <p>This is a simple representation of the transaction aspect logic implemented by Spring.</p> <pre><code>try { // your method's logic, part A } catch (RuntimeException e) { // rollback logic, part B } </code></pre> <p>If you handle the exception directly inside the method's logic (part A), it won't reach the catch block (part B). The aspect will never know that your method had an error, and thus, your changes will be committed, and no rollback will happen.</p> <h2>Wrap Up</h2> <p>Congrats on making it to the end. I hope this short tutorial gives you an idea of how transaction work, and how important it is in a real-world application.</p> javaspringVincent TaneriLeetCode: Add Two Numbers With TypeScripthttps://vitaneri.com/posts/leetcode-add-two-numbers-with-typescript/https://vitaneri.com/posts/leetcode-add-two-numbers-with-typescript/Going over `Add Two Numbers` from LeetCode with TypeScript.Sun, 09 Oct 2022 15:07:17 GMT<p>In this post, we'll be solving "Add Two Numbers" from LeetCode.</p> <p>The title sounds so simple but it's actually much more challenging then it sounds because we're dealing with linked list.</p> <blockquote> <p>A linked list is a sequence of nodes that contain two fields: an integer value and a link to the next node.</p> </blockquote> <p></p> <p>Now, let's go and solve the problem!</p> <h2>Problem</h2> <p>You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.</p> <p>You may assume the two numbers do not contain any leading zero, except the number 0 itself.</p> <p>Example 1:</p> <pre><code>Input: l1 = [2,4,3], l2 = [5,6,4] Output: [7,0,8] Explanation: 342 + 465 = 807. </code></pre> <p>Example 2:</p> <pre><code>Input: l1 = [0], l2 = [0] Output: [0] </code></pre> <p>Example 3:</p> <pre><code>Input: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] Output: [8,9,9,9,0,0,0,1] </code></pre> <p>Constraints:</p> <ul> <li>The number of nodes in each linked list is in the range <code>[1, 100]</code>.</li> <li><code>0 &lt;= Node.val &lt;= 9</code></li> <li>It is guaranteed that the list represents a number that does not have leading zeros.</li> </ul> <h2>Solution</h2> <h3>Analysis</h3> <p>This is a simple addition problem.</p> <p></p> <p>But in the linked list version, the numbers are sorted in reverse. That means we have to do our addition in reverse too.</p> <p></p> <h3>Approach</h3> <ol> <li>Create a dummy list node that'll point to our answer (This value should never change).</li> <li>Create a cursor that'll manage our answer's linked list.</li> <li>Traverse both list, but when the list is <code>null</code>, we replace the value with <code>0</code>. Just like in real world addition (no number is equal to 0).</li> <li>When traversing through the list, we add the number normally while also keeping track of the <code>carry</code>.</li> <li>After the addition is performed, have our cursor point to the addition result.</li> <li>Repeat until both list are traversed (both list are <code>null</code>).</li> <li>There might be an extra carry after the last addition, Let's not forget to handle that!</li> <li>Finally, return what our dummy list node from step 1 is pointing to.</li> </ol> <h3>Code</h3> <p>First, let's look at how our linked list is constructed:</p> <pre><code>class ListNode { val: number next: ListNode | null constructor(val?: number, next?: ListNode | null) { this.val = (val===undefined ? 0 : val) this.next = (next===undefined ? null : next) } </code></pre> <p>Now, for the solution:</p> <pre><code>function addTwoNumbers(l1: ListNode | null, l2: ListNode | null): ListNode | null { const answerHead = new ListNode(); let cursor = answerHead; let carry = 0; while (l1 !== null || l2 !== null) { const x = l1 ? l1.val : 0; const y = l2 ? l2.val : 0; const sum = x + y + carry; carry = sum &gt;= 10 ? 1 : 0; cursor.next = new ListNode(sum % 10); cursor = cursor.next; if (l1 != null) l1 = l1.next; if (l2 != null) l2 = l2.next; } if (carry &gt; 0) { cursor.next = new ListNode(carry); } return answerHead.next; } </code></pre> <h3>Time Complexity</h3> <p>The time complexity is <code>O(Max(m, n))</code> because both of the list will only be traversed once, and the complexity depends on which list is longer.</p> <h3>Space Complexity</h3> <p>The space complexity is <code>O(1)</code> because we're using space only for our variables.</p> <h2>Wrap Up</h2> <p>That's it for LeetCode's "Add Two Numbers" 🎉.</p> <p>You can also find the code on my <a href="https://github.com/tanerijun/ts-leetcode">Github</a>.</p> leetcodedsatypescriptVincent TaneriLeetCode: Container With Most Water With TypeScripthttps://vitaneri.com/posts/leetcode-container-with-most-water-with-typescript/https://vitaneri.com/posts/leetcode-container-with-most-water-with-typescript/Going over `Container With Most Water` from LeetCode with TypeScript.Thu, 27 Oct 2022 05:34:34 GMT<p>In this post, we're going to solve LeetCode's "Container With Most Water" using TypeScript.</p> <h2>Problem</h2> <p>You are given an integer array height of length <code>n</code>. There are <code>n</code> vertical lines drawn such that the two endpoints of the ith line are <code>(i, 0)</code> and <code>(i, height[i])</code>.</p> <p>Find two lines that together with the x-axis form a container, such that the container contains the most water.</p> <p>Return the maximum amount of water a container can store.</p> <p><strong>Notice</strong> that you may not slant the container.</p> <p>Example 1:</p> <p></p> <pre><code>Input: height = [1,8,6,2,5,4,8,3,7] Output: 49 Explanation: The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49. </code></pre> <p>Example 2:</p> <pre><code>Input: height = [1,1] Output: 1 </code></pre> <h2>Solution</h2> <p>Let's start by solving the problem with brute force so that it's more apparent why we need the more performant solution.</p> <h3>Brute Force</h3> <p>For the brute force approach, we just have to calculate all the possibles area from all the line combinations, and get the maximum value.</p> <pre><code>function maxArea(height: number[]): number { let max: number = 0; for (let i = 0; i &lt; height.length; i++) { for (let j = i + 1; j &lt; height.length; j++) { const w = j - i; const h = Math.min(height[i], height[j]); max = Math.max(max, w * h); } } return max; } </code></pre> <p>The time complexity for the brute force approach is <code>O(n^2)</code>.</p> <p>We can surely do better.</p> <h3>Two Pointers</h3> <p>For this approach, we have two pointers that start off at the edges of the array (the start and the end of the array). We then keep moving the pointers inwards, trying to find the largest area.</p> <pre><code>function maxArea(height: number[]): number { let max: number = 0; let l: number = 0; let r: number = height.length - 1; while (l &lt; r) { const w = r - l; const h = Math.min(height[l], height[r]); max = Math.max(max, w * h); if (height[l] &lt; height[r]) { l++; } else { r--; } } return max; } </code></pre> <p>If you're not sure why we have to move the shorter line pointer, it's because our calculation is based on it. If we try to move the longer line inwards, there'll be no increase in area. But if we move the shorter line, it might turn into a longer one, so the area will change.</p> <p>The time complexity for this approach is <code>O(n)</code> as we are only going through the array once.</p> <h2>Wrap Up</h2> <p>That's it for LeetCode's "Container With Most Water" 🎉.</p> <p>You can also find the code on my <a href="https://github.com/tanerijun/ts-leetcode">Github</a>.</p> leetcodedsatypescriptVincent TaneriLeetCode: Longest Palindromic Substring With TypeScripthttps://vitaneri.com/posts/leetcode-longest-palindromic-substring-with-typescript/https://vitaneri.com/posts/leetcode-longest-palindromic-substring-with-typescript/Going over 'Longest Palindromic Substring' from LeetCode with TypeScript.Sat, 22 Oct 2022 01:51:06 GMT<p>In this post, we are going to look at the solution to the "Longest Palindromic Substring" from LeetCode using TypeScript.</p> <h2>Problem</h2> <p>Given a string <code>s</code>, return the longest palindromic substring in <code>s</code>.</p> <p>A string is called a palindrome string if the reverse of that string is the same as the original string.</p> <p>Example 1:</p> <pre><code>Input: s = "babad" Output: "bab" Explanation: "aba" is also a valid answer. </code></pre> <p>Example 2:</p> <pre><code>Input: s = "cbbd" Output: "bb" </code></pre> <h2>Approach</h2> <h3>Brute Force</h3> <p>First, let's talk about the brute force method. We can loop through each substring and check if it's a palindrome.</p> <p>To do that:</p> <ul> <li>Create a variable to hold the longest palindrome string.</li> <li>Loop through each character in the string. <ul> <li>For each character, we loop through all the characters next to it to get every possible substring. <ul> <li>Inside each substring loop, we check whether it's a palindrome string or not.</li> <li>If it is, we check whether it's longer than our current palindrome and replace it if it is indeed longer.</li> </ul> </li> </ul> </li> <li>Return the longest palindrome.</li> </ul> <p>Take the string <code>"babad"</code> for example. Running the string through our algorithm will produce a loop like this, and for each loop we're going to check whether it's a palindrome or not.</p> <pre><code>b ba bab baba babad a ab ... </code></pre> <p>To check whether a string is a palindrome, we'll have to loop through each character in the string. Therefore the time complexity is <code>O(n)</code>.</p> <p>The check for each substring is a loop with a nested loop. Therefore the time complexity is <code>O(n2)</code>.</p> <p>If we put everything together, the time complexity is <code>O(n * n2)</code>, which is equal to <code>O(n3)</code>.</p> <p>There must be a better way to solve this.</p> <h3>Expand Around Center</h3> <p>The idea around this is that we'll check for palindrome by thinking of each character in the string as a center point and expanding from it.</p> <p>Take the string <code>"babad"</code> for example.</p> <ul> <li>First we take the first char <code>b</code> as a center point and expand it. We'll get <code>"*ba"</code> (<code>*</code> means empty) which is not a palindrome.</li> <li>Move to the next char <code>a</code> and expand it. We'll get <code>"bab"</code>, that's a palindrome. Try expanding again, and we get <code>"*baba"</code>, not a palindrome. So far the longest palindromic substring is <code>"bab"</code>.</li> <li>Continue doing this for the rest of the chars.</li> </ul> <p>But wait, there's also an even palindrome. For the string <code>"cbbd"</code>, <code>"bb"</code> is a valid answer. How are we going to check for this? For this one our other pointer have to be a spot ahead of the other pointer. It's hard to describe with words, but it'll be clear when we look at the code.</p> <p>The point is that we have to handle 2 separate cases, the odd palindrome and the even palindrome.</p> <p>By solving the problem this way, the time complexity of our algorithm is going to be much better than the brute-force method. The check for each character is <code>O(n)</code> and the expansion from center for each character is also <code>O(n)</code>. Therefore our time complexity is <code>O(n2)</code>.</p> <h2>Solution</h2> <p>Translating the approach to code:</p> <pre><code>function expandAroundCenter(s: string, l: number, r: number): number { while (l &gt;= 0 &amp;&amp; r &lt; s.length &amp;&amp; s[l] === s[r]) { l--; r++; } return r - l - 1; } export function longestPalindrome(s: string): string { if (s.length &lt;= 1) return s; // Keep track of the answer let lIdx = 0; let rIdx = 0; for (let i = 0; i &lt; s.length; i++) { let caseOdd = expandAroundCenter(s, i, i); // ex: "babad" let caseEven = expandAroundCenter(s, i, i + 1); // ex: "abbd" const len = Math.max(caseOdd, caseEven); if (len &gt; rIdx - lIdx) { lIdx = i - Math.floor((len - 1) / 2); rIdx = i + Math.floor(len / 2); } } return s.slice(lIdx, rIdx + 1); } </code></pre> <h2>Code Explanation</h2> <p>Let's explain the code in more detail.</p> <p>First, let's start with the <code>expandAroundCenter()</code> function.</p> <pre><code>function expandAroundCenter(s: string, l: number, r: number): number { while (l &gt;= 0 &amp;&amp; r &lt; s.length &amp;&amp; s[l] === s[r]) { l--; r++; } return r - l - 1; } </code></pre> <p>This part is pretty straightforward, the function simply take the <code>l</code> and <code>r</code> pointer we passed in, and keep moving them to the left and right respectively until their value is no longer the same or they go out of the string.</p> <p>The confusing part is probably the return calculation. It might not be obvious for some why the formula for calculating the length of the palindrome is <code>r - l - 1</code>.</p> <p>Let's take the string <code>"babad"</code> as an example. When we're on the second loop (<code>i = 1</code>), The function is called like this, <code>expandAroundCenter("babad", 1, 1)</code>. Now let's jump into the function and see how it executes.</p> <p>The first while loop will pass as <code>s[1] === s[1]</code> is <code>true</code>. Our <code>l</code> and <code>r</code> is now <code>0</code> and <code>2</code> respectively. At this point our instinct is to calculate the length like this <code>r - l + 1 = 2 - 0 + 1 = 3</code> which is correct.</p> <p>But our loop was executed again. Our <code>l</code> and <code>r</code> is now <code>-1</code> and <code>3</code> respectively. Then our while loop stop executing because the condition is no longer <code>true</code>. At this point, if we still use this formula <code>r - l + 1</code>, we'll get <code>3 - (-1) + 1 = 5</code>, which is incorrect. But a point to be noted here is that it give us our length increased by 2.</p> <p>It make sense why it's <code>+2</code>, right? It's because on the final loop, we still decrement <code>l</code> by 1 and increment <code>r</code> by 1. So to get the correct value, we have to subtract 2 from the answer. <code>r - l + 1 - 2 = r - l - 1</code>.</p> <p>Next, let's talk about the main function.</p> <pre><code>export function longestPalindrome(s: string): string { if (s.length &lt;= 1) return s; // Keep track of the answer let lIdx = 0; let rIdx = 0; for (let i = 0; i &lt; s.length; i++) { let caseOdd = expandAroundCenter(s, i, i); // ex: babad let caseEven = expandAroundCenter(s, i, i + 1); // ex: abbd const len = Math.max(caseOdd, caseEven); if (len &gt; rIdx - lIdx) { lIdx = i - Math.floor((len - 1) / 2); rIdx = i + Math.floor(len / 2); } } return s.slice(lIdx, rIdx + 1); } </code></pre> <ul> <li>The longest palindrome of a single character string is the string itself. And the longest palindrome of an empty string is just an empty string. Let's handle that first.</li> <li>Create two variables to track our answer. (Take <code>"babad"</code> as our input. If our answer is <code>"aba"</code>, then <code>lIdx = 1, rIdx = 3</code>.)</li> <li>Loop through each characters in the string. <ul> <li>Find the length of the longest palindrome using our <code>expandAroundCenter()</code> function.</li> <li>Since we don't know what kind of string we are given, we need to handle all case. (<code>"babad"</code> and <code>"cbbd"</code> need to be handled differently.)</li> <li>We then find the longest of the two.</li> <li>We update our <code>lIdx</code> and <code>rIdx</code> if the length is larger than the current value.</li> </ul> </li> <li>Finally, we return the palindrome substring and don't forget to add 1 to <code>rIdx</code> because slice is exclusive.</li> </ul> <p>If the part where we update our <code>lIdx</code> and <code>rIdx</code> is confusing, we can take a look at an example to make it clear.</p> <p>Assume that our input string is <code>"babad"</code>, and we're now at the second loop (<code>i = 1</code>). At this point the value of len is <code>3</code>. With 3 as length and <code>i = 1</code> as a center. We know that <code>lIdx</code> and <code>rIdx</code> have to be <code>0</code> and <code>2</code> respectively in order to produce the string <code>"bab"</code>.</p> <p>To calculate the left index, we need to subtract <code>i</code> with <code>Math.floor((len - 1) / 2)</code>, and to calculate the right index, we need to add <code>i</code> with <code>Math.floor(len / 2)</code>. The floor operation is necessary to prevent the division from resulting in floating point number.</p> <h2>Wrap Up</h2> <p>That's it for LeetCode's "Longest Palindromic String" 🎉.</p> <p>And if you want to make the algorithm even faster, you can research <a href="https://en.wikipedia.org/wiki/Longest_palindromic_substring#Manacher's_algorithm">The Manacher's Algorithm</a> for a <code>O(n)</code> solution.</p> <p>You can also find the code from this post on my <a href="https://github.com/tanerijun/ts-leetcode">Github</a>.</p> leetcodedsatypescriptVincent TaneriLeetCode: Longest Substring Without Repeating Characters With TypeScripthttps://vitaneri.com/posts/leetcode-longest-substring-without-repeating-characters-with-typescript/https://vitaneri.com/posts/leetcode-longest-substring-without-repeating-characters-with-typescript/Going over 'Longest Substring Without Repeating Characters' from Leetcode with Typescript.Fri, 21 Oct 2022 08:18:28 GMT<p>This is my solution to "Longest Substring Without Repeating Characters" from LeetCode with TypeScript.</p> <h2>Problem</h2> <p>Given a string <code>s</code>, find the length of the longest substring without repeating characters.</p> <p>Example 1:</p> <pre><code>Input: s = "abcabcbb" Output: 3 Explanation: The answer is "abc", with the length of 3. </code></pre> <p>Example 2:</p> <pre><code>Input: s = "bbbbb" Output: 1 Explanation: The answer is "b", with the length of 1. </code></pre> <p>Example 3:</p> <pre><code>Input: s = "pwwkew" Output: 3 Explanation: The answer is "wke", with the length of 3. Notice that the answer must be a substring, "pwke" is a subsequence and not a substring. </code></pre> <h2>Approach</h2> <p>To solve this problem efficiently. We have to use the sliding window algorithm, otherwise we'll have to deal with nested loops and our runtime complexity will increase exponentially. This algorithm, on the other hand, allows us to solve this problem in <code>O(n)</code> time complexity.</p> <p>These are the steps that we'll take to solve this problem:</p> <ul> <li>Create a variable to store our result (longest substring without repetition).</li> <li>Create a hash map to store our char with its index.</li> <li>Loop through all the characters in the string with 2 hands (<code>i</code>, <code>j</code>). <ul> <li>Check if the character already exist in the map.</li> <li>If it already exist: <ul> <li>We slide our left hand (<code>i</code>) to the current index of the char.</li> <li>But we need to compare it with its current value, and only update if the index of the duplicated char is larger than the current value of <code>i</code> (more on this below).</li> </ul> </li> <li>If it doesn't exist yet: <ul> <li>We add the character with its index to the map.</li> <li>We also slide our right hand (<code>j</code>) 1 step to the right.</li> <li>We update our result, which is the maximum of its current value and the range between the left hand and the right hand (<code>j - i + 1</code>).</li> </ul> </li> </ul> </li> <li>Return the result variable.</li> </ul> <h2>Solution</h2> <p>Translating our approach to code:</p> <pre><code>export function lengthOfLongestSubstring(s: string): number { let res = 0; const map = new Map&lt;string, number&gt;(); for (let i = 0, j = 0; j &lt; s.length; j++) { const char = map.get(s[j]); if (char) { i = Math.max(char, i); } map.set(s[j], j + 1); res = Math.max(res, j - i + 1); } return res; } </code></pre> <h2>Bonus</h2> <p>Why do we need to compare the current value of <code>i</code> in line 8 before updating it to the index of the duplicated char? Shouldn't <code>i = char</code> suffice?</p> <p>The reason I want to talk about this is because I stumbled upon a bug on my first try because I did that. I wrote my code like this.</p> <pre><code>export function lengthOfLongestSubstring(s: string): number { let res = 0; const map = new Map&lt;string, number&gt;(); for (let i = 0, j = 0; j &lt; s.length; j++) { const char = map.get(s[j]); if (char) { i = char; } map.set(s[j], j + 1); res = Math.max(res, j - i + 1); } return res; } </code></pre> <p>If you're like me, you might find the explanation below helpful.</p> <p>To see the bug produced by this code, let's track how the loop run if the input string is <code>"abba"</code>.</p> <ul> <li>Loop 1 add <code>a</code> to map because the char doesn't exist yet. Our <code>i</code> is 0 and our result is 1.</li> <li>Loop 2 add <code>b</code> to map because the char doesn't exist yet. Our <code>i</code> is 0 and our result is now 2.</li> <li>Loop 3 found that <code>b</code> already exist in our map. So we assign the index of <code>b</code> which is 1 to <code>i</code>. Our <code>i</code> is now 1, and our result is now 2. (Correct behavior)</li> <li>Loop 4 found that <code>a</code> already exist in our map. So we move our <code>i</code> to the index of <code>a</code> which is 0. Our <code>i</code> is now back to 0 and our result is now 3. (<code>i</code> shouldn't move back to the left)</li> </ul> <p>Now you get why we need <code>Math.max</code> there. Both our <code>i</code> and <code>j</code> should only move to the right, getting closer and closer to the end of the input string.</p> <h2>Wrap Up</h2> <p>That's it for LeetCode's "Longest Substring Without Repeating Characters" 🎉.</p> <p>You can also find the code on my <a href="https://github.com/tanerijun/ts-leetcode">Github</a>.</p> leetcodedsatypescriptVincent TaneriLeetCode: Palindrome Number With TypeScripthttps://vitaneri.com/posts/leetcode-palindrome-number-with-typescript/https://vitaneri.com/posts/leetcode-palindrome-number-with-typescript/Going over 'Palidrome Number' from Leetcode with Typescript.Wed, 26 Oct 2022 05:39:32 GMT<p>In this post, we're going to solve LeetCode's "Palindrome Number" using TypeScript.</p> <h2>Problem</h2> <p>Given an integer <code>x</code>, return <code>true</code> if <code>x</code> is palindrome integer.</p> <ul> <li>For example, <code>121</code> is a palindrome while <code>123</code> is not.</li> </ul> <p>Example 1:</p> <pre><code>Input: x = 121 Output: true Explanation: 121 reads as 121 from left to right and from right to left. </code></pre> <p>Example 2:</p> <pre><code>Input: x = -121 Output: false Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome. </code></pre> <p>Example 3:</p> <pre><code>Input: x = 10 Output: false Explanation: Reads 01 from right to left. Therefore it is not a palindrome. </code></pre> <p>Constraints:</p> <ul> <li><code>-2^31 &lt;= x &lt;= 2^31 - 1</code></li> </ul> <p><strong>Follow up</strong>: Could you solve it without converting the integer to a string?</p> <h2>Approach</h2> <p>Our aim is to solve this without converting the integer to a string. If you're already familiar with our solution for LeetCode's <a href="https://vitaneri.com/posts/leetcode-reverse-integer-with-typescript/">Reverse Integer</a>, this problem is going to be a breeze because we solved that problem without converting the integer to a string.</p> <p>But this time, instead of reversing the whole integer, we only have to reverse half of the digits. We can then compare those half, and see if they are the same (palindrome).</p> <p>And in the case where there are odd numbers of digits in the integer, we can ignore the middle digit because it will always equal to itself.</p> <h2>Solution</h2> <p>Translating our approach to code:</p> <pre><code>function isPalindrome(x: number): boolean { if (x &lt; 0 || (x % 10 === 0 &amp;&amp; x != 0)) return false; let reversed: number = 0; while (x &gt; reversed) { reversed = reversed * 10 + (x % 10); x = Math.trunc(x / 10); } return reversed === x || Math.trunc(reversed / 10) === x; } </code></pre> <h2>Wrap Up</h2> <p>That's it for LeetCode's "Palindrome Number" 🎉.</p> <p>You can also find the code on my <a href="https://github.com/tanerijun/ts-leetcode">Github</a>.</p> leetcodedsatypescriptVincent TaneriLeetCode: Reverse Integer With TypeScripthttps://vitaneri.com/posts/leetcode-reverse-integer-with-typescript/https://vitaneri.com/posts/leetcode-reverse-integer-with-typescript/Going over 'Reverse Integer' from Leetcode with Typescript.Mon, 24 Oct 2022 14:06:23 GMT<p>In this post, we're going to solve LeetCode's "Reverse Integer" using TypeScript.</p> <h2>Problem</h2> <p>Given a signed 32-bit integer x, return x with its digits reversed. If reversing x causes the value to go outside the signed 32-bit integer range [-231, 231 - 1], then return 0.</p> <p><strong>Assume the environment does not allow you to store 64-bit integers (signed or unsigned).</strong></p> <p>Example 1:</p> <pre><code>Input: x = 123 Output: 321 </code></pre> <p>Example 2:</p> <pre><code>Input: x = -123 Output: -321 </code></pre> <p>Example 3:</p> <pre><code>Input: x = 120 Output: 21 </code></pre> <p>Constraints:</p> <pre><code>-231 &lt;= x &lt;= 231 - 1 </code></pre> <h2>Approach</h2> <p>We can simply convert the number to string, split it into array of characters, reverse the array, then join them back together. After that we have to multiply the result with -1 if the input is negative.</p> <p>But the method above is not really efficient as we're doing multiple array's <code>O(n)</code> operation.</p> <p>We can also solve this problem with simple arithmetic. First, it's important to understand this concept:</p> <ul> <li>You can add a digit to a number by multiplying the number with 10 and adding the digit to the number.</li> <li>You can remove the last digit of a number by dividing with 10 and removing the fractional value.</li> </ul> <p>Now, this is how we are going to solve it:</p> <ul> <li>First, convert the number to positive because it's easier to work with.</li> <li>Create a variable to store our result.</li> <li>Run a loop until input number is equal to 0. <ul> <li>We append the last digit of the input number to our result variable.</li> <li>We remove the last digit from the input number (the input will eventually become 0 this way).</li> </ul> </li> <li>Multiply the result with -1 if the input number is negative.</li> <li>Check if the result exceed the maximum size of signed 32-bit integer, and return the result.</li> </ul> <p>The time complexity for this approach is <code>O(log(x))</code>. Because the complexity depends on the number of digits in <code>x</code>, and it can roughly be represented with <code>log(x)</code>.</p> <h2>Solution</h2> <h3>Converting To String</h3> <pre><code>function reverse(x: number): number { const reversed = x.toString().split("").reverse().join(""); const result = parseInt(reversed) * Math.sign(x); if (result &lt; Math.pow(-2, 31) || result &gt; Math.pow(2, 31) - 1) return 0; return result; } </code></pre> <h3>Using Arithmetic</h3> <pre><code>function reverse(x: number): number { let input = Math.abs(x); let result: number = 0; while (input != 0) { result = result * 10 + (input % 10); input = Math.floor(input / 10); } result *= Math.sign(x); if (result &lt; Math.pow(-2, 31) || result &gt; Math.pow(2, 31) - 1) return 0; return result; } </code></pre> <h2>Wrap Up</h2> <p>That's it for LeetCode's "Reverse Integer" 🎉.</p> <p>You can also find the code on my <a href="https://github.com/tanerijun/ts-leetcode">Github</a>.</p> leetcodedsatypescriptVincent TaneriLeetCode: String To Integer (atoi) With TypeScripthttps://vitaneri.com/posts/leetcode-string-to-integer-atoi-with-typescript/https://vitaneri.com/posts/leetcode-string-to-integer-atoi-with-typescript/Going over 'String To Integer (atoi)' from Leetcode with Typescript.Tue, 25 Oct 2022 13:55:29 GMT<p>In this post, we're going to solve LeetCode's "String To Integer (atoi)" using TypeScript.</p> <h2>Problem</h2> <p>Implement the <code>myAtoi(string s)</code> function, which converts a string to a 32-bit signed integer (similar to C/C++'s <code>atoi</code> function).</p> <p>The algorithm for <code>myAtoi(string s)</code> is as follows:</p> <ol> <li>Read in and ignore any leading whitespace.</li> <li>Check if the next character (if not already at the end of the string) is <code>'-'</code> or <code>'+'</code>. Read this character in if it is either. This determines if the final result is negative or positive respectively. Assume the result is positive if neither is present.</li> <li>Read in next the characters until the next non-digit character or the end of the input is reached. The rest of the string is ignored.</li> <li>Convert these digits into an integer (i.e. <code>"123" -&gt; 123</code>, <code>"0032" -&gt; 32</code>). If no digits were read, then the integer is <code>0</code>. Change the sign as necessary (from step 2).</li> <li>If the integer is out of the 32-bit signed integer range <code>[-2^31, 2^31 - 1]</code>, then clamp the integer so that it remains in the range. Specifically, integers less than <code>-2^31</code> should be clamped to <code>-2^31</code>, and integers greater than <code>2^31 - 1</code> should be clamped to <code>2^31 - 1</code>.</li> <li>Return the integer as the final result.</li> </ol> <p><strong>Note:</strong></p> <ul> <li>Only the space character <code>' '</code> is considered a whitespace character.</li> <li><strong>Do not ignore</strong> any characters other than the leading whitespace or the rest of the string after the digits.</li> </ul> <h2>Approach</h2> <p>Since the algorithm has been given to us, all we need to do is to implement it.</p> <h2>Solution</h2> <pre><code>function myAtoi(s: string): number { const input: string = s.trimStart(); let result: number = 0; let sign: number | undefined; if (input[0] === "+") { sign = 1; } else if (input[0] === "-") { sign = -1; } let i = sign ? 1 : 0; for (; i &lt; input.length; i++) { const num = parseInt(input[i]); if (num &gt;= 0 &amp;&amp; num &lt;= 9) { result = result * 10 + num; } else { break; } } result = sign === -1 ? result * -1 : result; const MAX_VAL = Math.pow(2, 31) - 1; const MIN_VAL = Math.pow(-2, 31); if (result &gt; MAX_VAL) { result = MAX_VAL; } else if (result &lt; MIN_VAL) { result = MIN_VAL; } return result; } </code></pre> <h2>Code Explanation</h2> <ol> <li>Remove leading whitespace from the string.</li> <li>Create a variable to store the result.</li> <li>Create a variable to temporary store whether the input is a positive or negative number.</li> <li>Loop through each characters in the string without forgetting to adjust the starting point according to if the positive or negative sign is available. <ol> <li>Add the char to the result variable if it's a number.</li> <li>Otherwise, we break the loop.</li> </ol> </li> <li>Multiply result with <code>-1</code> if the input was a negative number.</li> <li>Clamp the result to the 32-bit signed integer range if it exceeds the range.</li> <li>Return the result.</li> </ol> <h2>Wrap Up</h2> <p>That's it for LeetCode's "String To Integer (atoi)" 🎉.</p> <p>You can also find the code on my <a href="https://github.com/tanerijun/ts-leetcode">Github</a>.</p> leetcodedsatypescriptVincent TaneriLeetCode: Two Sum With TypeScripthttps://vitaneri.com/posts/leetcode-two-sum-with-typescript/https://vitaneri.com/posts/leetcode-two-sum-with-typescript/Going over 'Two Sum' from Leetcode with Typescript.Sat, 08 Oct 2022 13:39:18 GMT<p>In this post, we're going to look at LeetCode's Two Sum problem and find the most efficient algorithm to solve the problem.</p> <h2>Problem</h2> <p>Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.</p> <p>You may assume that each input would have exactly one solution, and you may not use the same element twice.</p> <p>You can return the answer in any order.</p> <p>Example 1:</p> <pre><code>Input: nums = [2,7,11,15], target = 9 Output: [0,1] Explanation: Because nums[0] + nums[1] == 9, we return [0, 1]. </code></pre> <p>Example 2:</p> <pre><code>Input: nums = [3,2,4], target = 6 Output: [1,2] </code></pre> <p>Example 3:</p> <pre><code>Input: nums = [3,3], target = 6 Output: [0,1] </code></pre> <h2>Solution</h2> <p>The answer to Two Sum is really easy to come by. But that obvious answer is a trap, it's not the most efficient solution.</p> <p>I am talking about the brute force method. Something like this:</p> <pre><code>function twoSum(nums: number[], target: number): number[] { for (let i = 0; i &lt; nums.length; i++) { for (let j = 0; j &lt; nums.length; j++) { if (nums[i] + nums[j] === target) { return [i, j]; } } } return []; } </code></pre> <p>Notice that we're using two loops, that's never a good solution. The time complexity will be <code>O(n2)</code>. In other words, as the list grow larger and larger, the algorithm is going to be exponentially slower.</p> <p>We want to try solving this only by looping through the list once, and we can achieve that with the help of a hash map.</p> <pre><code>function twoSum(nums: number[], target: number): number[] { const map: Map&lt;number, number&gt; = new Map(); for (let i = 0; i &lt; nums.length; i++) { const complement = target - nums[i]; const complementIndex = map.get(complement); if (complementIndex !== undefined) { return [complementIndex, i]; } map.set(nums[i], i); } return []; } </code></pre> <p>Now that we're using a hash map, the time complexity is down to <code>O(n)</code> (where <code>n</code> represents the length of the array). In the worst case, each element in the array will be visited once before we get our answer. ß As for space complexity, it's also <code>O(n)</code>. In the worst case, the algorithm will have to put each number from the array into the map.</p> <h2>Wrap Up</h2> <p>That's it for Two Sum with TypeScript. 🎉</p> <p>You can also find the code on my <a href="https://github.com/tanerijun/ts-leetcode">Github</a>.</p> leetcodedsatypescriptVincent TaneriLeetCode: Zigzag Conversion With TypeScripthttps://vitaneri.com/posts/leetcode-zigzag-conversion-with-typescript/https://vitaneri.com/posts/leetcode-zigzag-conversion-with-typescript/Going over 'Zigzag Conversion' from Leetcode with Typescript.Sun, 23 Oct 2022 05:37:15 GMT<p>In this post, we are going to look at my solution to the "Zigzag Conversion" from LeetCode using TypeScript.</p> <h2>Problem</h2> <p>The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)</p> <pre><code>P A H N A P L S I I G Y I R </code></pre> <p>And then read line by line: "PAHNAPLSIIGYIR"</p> <p>Write the code that will take a string and make this conversion given a number of rows:</p> <pre><code>string convert(string s, int numRows); </code></pre> <p>Example 1:</p> <pre><code>Input: s = "PAYPALISHIRING", numRows = 3 Output: "PAHNAPLSIIGYIR" </code></pre> <p>Example 2:</p> <pre><code>Input: s = "PAYPALISHIRING", numRows = 4 Output: "PINALSIGYAHRPI" Explanation: P I N A L S I G Y A H R P I </code></pre> <p>Example 3:</p> <pre><code>Input: s = "A", numRows = 1 Output: "A" </code></pre> <h2>Approach</h2> <p>We can forget about all the zigzag stuff and think of the problem as rows of string instead. We simply have to loop through each character and concatenate it to the appropriate string.</p> <p>For example, the conversion of <code>"PAYPALISHIRING"</code> with 3 rows is</p> <pre><code>P A H N A P L S I I G Y I R </code></pre> <p>The pattern above is the same as (considering that we're going to join them line by line in the end)</p> <pre><code>"PAHN", "APLSIIG", "YIR" </code></pre> <p>And finally, we can concatenate the strings and get <code>"PAHNAPLSIIGYIR"</code>.</p> <p>The time complexity of this approach is <code>O(n)</code> where <code>n</code> equals the length of the input string.</p> <h2>Solution</h2> <p>Translating our approach to code:</p> <pre><code>function convert(s: string, numRows: number): string { const resArr: string[] = Array(numRows).fill(""); let cursor: number = 0; let isDecreasing: boolean = false; for (let i = 0; i &lt; s.length; i++) { resArr[cursor] += s[i]; if (cursor === 0) { isDecreasing = false; } if (cursor === numRows - 1) { isDecreasing = true; } if (isDecreasing) { if (cursor != 0) cursor -= 1; } else { cursor += 1; } } return resArr.join(""); } </code></pre> <h2>Code Explanation</h2> <p>Let me explain the code:</p> <ul> <li>We create an array of empty string the size of the number of rows.</li> <li>We then create a cursor and a boolean flag to control whether the cursor should be increasing or decreasing.</li> <li>We loop through each character in the string. <ul> <li>We concatenate the char with the string that the current cursor is pointing at.</li> <li>We adjust the flag if needed.</li> <li>We modify the cursor based on the flag. <ul> <li>Note that the cursor shouldn't be a negative number, so we have an additional check before decreasing the cursor.</li> </ul> </li> </ul> </li> <li>We return all the string inside the array joined together.</li> </ul> <h2>Wrap Up</h2> <p>That's it for LeetCode's "Zigzag Conversion" 🎉. The result is also very satisfying.</p> <pre><code>Runtime: 101 ms, faster than 94.46% of TypeScript online submissions for Zigzag Conversion. Memory Usage: 46.3 MB, less than 98.99% of TypeScript online submissions for Zigzag Conversion. </code></pre> <p>You can also find the code on my <a href="https://github.com/tanerijun/ts-leetcode">Github</a>.</p> leetcodedsatypescriptVincent TaneriMake Image Fade To Transparent With CSShttps://vitaneri.com/posts/make-image-fade-to-transparent-with-css/https://vitaneri.com/posts/make-image-fade-to-transparent-with-css/A guide on how to make any image fade to transparent with CSS.Fri, 30 Sep 2022 01:15:16 GMT<p>In this post, we're going to take a look at how to make an image fade to transparent, or what I like to call <em>transparent image gradient</em> with CSS.</p> <h2>Example</h2> <p>This is an example of the effect we're trying to achieve.</p> <p></p> <p>Notice how the bottom part of the image is slowly fading into the background, making it much easier to read the text on top of it.</p> <h2>Solution</h2> <p>To achieve this effect, we'll need to use CSS masking, the <code>mask-image</code> property.</p> <p>Basically, we're creating a mask layer on top of an image to partially or fully hide portions of the image.</p> <p><em>Note: As of the time of writing this article (September 2022), most browsers only have partial support for CSS masking. So we need to add the <code>-webkit-</code> prefix in addition to the standard property in most browsers.</em></p> <p>Without further ado, here is the CSS that you need to apply to the image:</p> <pre><code>.transparent-gradient { -webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0)); mask-image: linear-gradient(180deg, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0)); } </code></pre> <p>You can also fine-tune the gradient direction by changing the first argument, and also the degree of transparency with the second and third arguments, more specifically, the <code>a</code> part of <code>rgba</code>, which stands for alpha (transparency).</p> <h2>Wrap Up</h2> <p>That's it 🎉. Hope you find it useful.</p> cssVincent TaneriOptimize React's useState Hook With Lazy Initializationhttps://vitaneri.com/posts/optimize-reacts-usestate-hook-with-lazy-initialization/https://vitaneri.com/posts/optimize-reacts-usestate-hook-with-lazy-initialization/A guide on optimizing React's performance using lazy initialization.Mon, 16 Jan 2023 14:18:32 GMT<p>In this post, we'll look at a way to optimize React's <code>useState</code> hook called <a href="https://reactjs.org/docs/hooks-reference.html#lazy-initial-state">lazy initialization</a>.</p> <h2>The Problem</h2> <p>So there's this method to optimize React's performance that I think is less-known (maybe it's just me 🫠) called <strong>lazy initialization</strong>. It's a way to optimize the React's <code>useState</code> hook.</p> <p>Let's start by looking at an example.</p> <pre><code>function NameForm = () =&gt; { const [name, setName] = useState( window.localStorage.getItem('name') ?? "" ) useEffect(() =&gt; { window.localStorage.setItem('name', name) }, [name]) return ( &lt;div&gt; &lt;form&gt; &lt;label htmlFor="name"&gt;Name: &lt;/label&gt; &lt;input value={name} onChange={handleChange} id="name" /&gt; &lt;/form&gt; {name} &lt;/div&gt; ) } </code></pre> <p>Let's see what's going on with the component. On render, we first check if there's already a previously stored value in the local storage and use it as the initial value for the <code>useState</code> hook. We also have a <code>useEffect</code> hook that update the local storage every time the name value is changed. And finally, we render an input and the name value to the screen.</p> <p>In short, it's just a simple component with input that take in your name and display it on the screen.</p> <p>In the example above, the <code>useState</code> hook read the value from local storage every time it re-renders. In this case, every time you type with the input box.</p> <p>As you know, reading from local storage is an IO operation, and it can potentially slow down our application.</p> <blockquote> <p>Reading from local storage is just one example. The same potential performance issue apply to any expensive function you passed to <code>useState</code>.</p> </blockquote> <p>The argument you pass to <code>useState</code> is supposed to be the initial value of the state. So, why is it that the function you passed need to re-run on every subsequent re-render? Is this React's bug?</p> <p>The answer is "No". The culprit here is Javascript itself.</p> <p>When your component re-renders, your function is parsed and executed again. When Javascript parses your component, it'll run the function you passed as argument, get its value, and passes it to <code>useState</code> again, which is then ignored correctly by React.</p> <p>As you can see, the problem occurred before you even reach the React land.</p> <p>So, how do we prevent Javascript from executing our function? <strong>Anonymous function</strong> to the rescue.</p> <p>It's just like passing an arrow function that executes your function instead of passing your function directly to event handlers when your function has argument.</p> <pre><code>&lt;button onClick={() =&gt; setValue(3)} /&gt; </code></pre> <p>Instead of</p> <pre><code>&lt;button onClick={setValue(3)} /&gt; // this will error, because the function executes too early </code></pre> <p>The same principle comes into play here. In this case though, it's called <strong>lazy initialization</strong>.</p> <p>When the Javascript parser see an anonymous function, it won't try to get its value. So your function argument to <code>useState</code> will truly only run once (on initial render, by React).</p> <p>To fix the example above:</p> <pre><code>function NameForm = () =&gt; { const [name, setName] = useState( () =&gt; window.localStorage.getItem('name') ?? "" ) useEffect(() =&gt; { window.localStorage.setItem('name', name) }, [name]) return ( &lt;div&gt; &lt;form&gt; &lt;label htmlFor="name"&gt;Name: &lt;/label&gt; &lt;input value={name} onChange={handleChange} id="name" /&gt; &lt;/form&gt; {name} &lt;/div&gt; ) } </code></pre> <p>Instead of passing the initial value directly to the <code>useState</code> hook, we passed in an anonymous function that returns the initial value instead.</p> <p>Now, the <code>useState</code> hook will only get the value from local storage on initial render. Which is really what we want it to do.</p> <h2>Wrap Up</h2> <p>This is a good performance optimization technique to use whenever the initial value for our <code>useState</code> hook is an expensive computation.</p> <p>Hope you find it useful 👍🏻.</p> javascriptreactVincent TaneriPreserve Case When Working With HTTP Headers in Gohttps://vitaneri.com/posts/preserve-case-when-working-with-http-headers-in-go/https://vitaneri.com/posts/preserve-case-when-working-with-http-headers-in-go/A guide on how to bypass the automatic canonicalization of HTTP headers in Go.Wed, 27 Dec 2023 14:47:43 GMT<p>When you're manipulating the HTTP headers with methods like <code>Set()</code>, <code>Add()</code>, etc., in Go, you'll find that they're automatically canonicalized. Canonicalization converts the first letter and any letter following a hyphen to uppercase, and every other letters to lowercase.</p> <p>For example:</p> <pre><code>w.Header().Set("my-api-key", "secret-key") </code></pre> <p>Will be transformed into this:</p> <pre><code>My-Api-Key: secret-key </code></pre> <p>This is caused by Go passing your key through <a href="https://pkg.go.dev/net/textproto#CanonicalMIMEHeaderKey"><code>CanonicalMimeHeaderKey</code></a> before calling your methods.</p> <p>This is fine and all as HTTP headers are case-insensitive. But sometimes, you might find yourself in a situation where you're forced to work with case-sensitive headers.</p> <p>In that case, you can modify the HTTP headers like this:</p> <pre><code>w.Header()["my-api-key"] = []string{"secret-key"} </code></pre> <p>This is possible because the Header's type is actually <code>map[string][]string</code>, meaning it's just a <code>map</code> with key of type <code>string</code> and value of type <code>[]string</code>.</p> goVincent TaneriRedirect STDOUT and STDERR in Linux Shellhttps://vitaneri.com/posts/redirect-stdout-and-stderr-in-linux-shell/https://vitaneri.com/posts/redirect-stdout-and-stderr-in-linux-shell/A guide on redirecting shell's output stream.Thu, 28 Dec 2023 15:47:37 GMT<p>Unix shells use three standard I/O streams, which are represented by numeric file descriptors:</p> <ul> <li><code>0</code> - <code>STDIN</code> - The standard input stream</li> <li><code>1</code> - <code>STDOUT</code> - The standard output stream</li> <li><code>2</code> - <code>STDERR</code> - The standard error stream</li> </ul> <p>By default, both <code>output</code> and <code>error</code> streams are printed straight to the terminal. But sometimes, we might prefer to redirect them to files for persistence.</p> <h2>Basic</h2> <p>To redirect the streams to files, we can use the <code>n&gt;</code> operator, where <code>n</code> is the file descriptor (in this case, either <code>1</code> or <code>2</code>).</p> <pre><code>command 1&gt; file_path command 2&gt; file_path </code></pre> <p>The first line redirects <code>STDOUT</code>, while the second line redirects <code>STDERR</code>.</p> <p>Of course, you can also redirect both <code>STDOUT</code> and <code>STDERR</code> at the same time by combining the operators.</p> <pre><code>command 1&gt; STDOUT.log 2&gt; STDERR.log </code></pre> <h2>Redirecting <code>STDOUT</code> and <code>STDERR</code> to the Same File</h2> <p>In the case where you need to redirect both <code>STDOUT</code> and <code>STDERR</code> to the same file, you can use this command.</p> <pre><code>command &gt; file_path 2&gt;&amp;1 </code></pre> <p>The <code>2&gt;&amp;1</code> construct translates to "send the STDERR to the same place you are sending the STDOUT."</p> <p>Pay attention to the order of redirection above. First, we redirect <code>STDOUT</code> to <code>file_path</code>, then we redirect <code>STDERR</code> to <code>STDOUT</code>.</p> <p>If we do it in reversed order, like <code>command 2&gt;&amp;1 &gt; file_path</code>, the command won't work as intended. <code>STDERR</code> is redirected to <code>STDOUT</code> which is still the terminal screen, then <code>STDOUT</code> is redirected to <code>file_path</code>.</p> <p>If you're using <code>Bash</code>, the more concise construct <code>&amp;&gt;</code> which is equal to <code>2&gt;&amp;1</code>.</p> <pre><code>command &amp;&gt; file_path </code></pre> <h2>Redirect and Append to File</h2> <p>In the case where you want to append to the end of the file instead of overwriting it, you can use the <code>&gt;&gt;</code> operator instead.</p> <pre><code>command &gt;&gt; info.log 2&gt;&gt; error.log </code></pre> <h2>Redirect to Another Process</h2> <p>You can also redirect to another process using the pipe (<code>|</code>) operator.</p> <pre><code>command1 | command2 | command3 </code></pre> <p>In this case, the output from <code>command1</code> will act as the input for <code>command2</code>, and the output from <code>command2</code> will also act as the input for <code>command3</code>, and so on.</p> <h2>Redirect to Nowhere</h2> <p>Finally, in the case where you need to redirect to nowhere due to reasons like very huge output, or if you just don't want to see the output, you can redirect to <code>/dev/null</code>.</p> <pre><code>command &gt; /dev/null command 2&gt; /dev/null </code></pre> <p>This works because <code>dev/null</code> is like the black hole of the Linux file system. Anything you throw there will never see the light again.</p> linuxVincent TaneriSetting Up Vitest, Testing Library, And jest-dom In Your Vite Projecthttps://vitaneri.com/posts/setting-up-vitest-testing-library-and-jest-dom-in-your-vite-project/https://vitaneri.com/posts/setting-up-vitest-testing-library-and-jest-dom-in-your-vite-project/A guide on setting up Vitest, Testing Library, and jest-dom for unit testing a Vite project.Fri, 06 Jan 2023 13:07:13 GMT<p>This will be a brief tutorial on how to setup Vitest, Testing Library, and jest-dom in your Vite Project.</p> <h2>Setup Vite Project</h2> <p>Before we can setup our testing tools, we first need a Vite project. We can scaffold a Vite project easily by running the command:</p> <pre><code>npm create vite@latest </code></pre> <p>Next, you'll be prompted for your project name, your front-end framework of choice, and whether you need Typescript or not.</p> <p>In this project, let's assume that we choose <a href="https://svelte.dev/">Svelte</a> as our front-end framework and Typescript as our language of choice.</p> <blockquote> <p>The steps are more or less the same regardless of what framework you're using.</p> </blockquote> <h2>Install Vitest</h2> <p>The next step is to install Vitest using the command:</p> <pre><code>npm install --save-dev vitest </code></pre> <p>We also need to install <code>jsdom</code> to simulate the DOM for our frontend app.</p> <pre><code>npm install --save-dev jsdom </code></pre> <p>Next, we need to tell Vitest to change our testing environment to <code>jsdom</code>. Create a file called <code>vitest.config.ts</code> or <code>.js</code> depending on your preferences, and pass the following code in.</p> <pre><code>import { defineConfig } from "vitest/config"; import { svelte } from "@sveltejs/vite-plugin-svelte"; export default defineConfig({ plugins: [svelte({ hot: !process.env.VITEST })], test: { include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], environment: "jsdom", }, }); </code></pre> <p>One thing to note about Vitest is that unlike Jest, globals are not enabled by default. This means that we have to explicitly import <code>describe</code>, <code>test</code>, <code>expect</code>, etc. on our test files like this:</p> <pre><code>import { describe, test, expect } from "vitest"; </code></pre> <p>But if you prefer, you can enable the test APIs globally like Jest. To enable globals support, we need to add the following line into our <code>vitest.config.ts</code> file.</p> <pre><code>import { defineConfig } from "vitest/config"; import { svelte } from "@sveltejs/vite-plugin-svelte"; export default defineConfig({ plugins: [svelte({ hot: !process.env.VITEST })], test: { include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], globals: true, environment: "jsdom", }, }); </code></pre> <p>If you're using Typescript, we need to do one extra step to please the type checker. We need to add <code>vitest/globals</code> to <code>compilerOptions</code> in <code>tsconfig.json</code>.</p> <pre><code>{ "extends": "@tsconfig/svelte/tsconfig.json", "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "resolveJsonModule": true, "allowJs": true, "checkJs": true, "isolatedModules": true, "moduleResolution": "node", "types": ["vitest/globals"] }, "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], "references": [{ "path": "./tsconfig.node.json" }] } </code></pre> <p>And finally, let's add the following to our <code>package.json</code> file for convenience sake.</p> <pre><code>{ "scripts": { "test": "vitest run src", "test:watch": "vitest src" } } </code></pre> <p>Now, we can run our tests with <code>npm run test</code> or <code>npm run test:watch</code> to run in watch mode.</p> <h2>Install Testing Library</h2> <p>Installing Vitest is enough to test our app. But <a href="https://testing-library.com/">Testing Library</a> offers us a lot of utilities that'll make our life easier.</p> <p>For example, the <code>render</code> method save us the trouble of creating a container, appending it to the body, and cleaning up the container after test, etc.</p> <p>Testing Library supports multiple framework. And since we're assuming that this is a Svelte project, we'll be using the <a href="https://testing-library.com/docs/svelte-testing-library/intro#">Svelte Testing Library</a>.</p> <pre><code>npm install --save-dev @testing-library/svelte </code></pre> <h2>Install jest-dom</h2> <p>jest-dom is a really nice addition on top of Testing Library. It's a custom matcher that's really useful to test the state of the DOM.</p> <blockquote> <p>Matcher is what you put after <code>expect</code>. For example: <code>expect(getByTestId('input')).toBeDisabled()</code>. <code>toBeDisabled()</code> is one of the useful matchers provided by jest-dom.</p> </blockquote> <p>Install it by running:</p> <pre><code>npm install --save-dev @testing-library/jest-dom </code></pre> <p>Now, we can use the matchers by importing <code>@testing-library/jest-dom</code> at the start of our test files.</p> <pre><code>import "@testing-library/jest-dom"; </code></pre> <p>We can make our experience even better by extending the matcher with a Vitest setup file. The filename doesn't matter, but let's assume that the file name is <code>./src/tests/setup.ts</code>. Inside the file, paste in the following code:</p> <pre><code>import { expect } from "vitest"; import matchers from "@testing-library/jest-dom/matchers"; expect.extend(matchers); </code></pre> <p>We also need to tell Vitest where to look for our setup file.</p> <pre><code>import { defineConfig } from "vitest/config"; import { svelte } from "@sveltejs/vite-plugin-svelte"; export default defineConfig({ plugins: [svelte({ hot: !process.env.VITEST })], test: { include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], globals: true, environment: "jsdom", setupFiles: "./src/tests/setup.ts", }, }); </code></pre> <p>Now, we don't need to manually import <code>@testing-library/jest-dom</code> anymore in our test files.</p> <p>One final thing before we end this tutorial.</p> <p>In my case, Typescript couldn't find the type definition for the matchers. So even though all my tests run just fine, I didn't get auto completion for the matcher in my IDE and got a squiggly red line instead.</p> <p>If you have the same issue, install the type definition for jest-dom.</p> <blockquote> <p>If you're not using Typescript, or don't experience this issue, you can skip this step.</p> </blockquote> <pre><code>npm install --save-dev @types/testing-library__jest-dom </code></pre> <p>And update your <code>tsconfig.json</code>.</p> <pre><code>{ "extends": "@tsconfig/svelte/tsconfig.json", "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "resolveJsonModule": true, "allowJs": true, "checkJs": true, "isolatedModules": true, "moduleResolution": "node", "types": ["vitest/globals", "@testing-library/jest-dom"] }, "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], "references": [{ "path": "./tsconfig.node.json" }] } </code></pre> <p>With that, everything should now work as expected 😁.</p> <h2>Wrap Up</h2> <p>That's it, we're done with our test setup. Now simply create your tests, and run it using the command:</p> <pre><code>npm run test </code></pre> <p>Happy testing!</p> vitestjavascripttypescriptVincent TaneriSolving "An import path cannot end with a .ts extension" When Using Deno With VSCodehttps://vitaneri.com/posts/solving-an-import-path-cannot-end-with-a-ts-extension-when-using-deno-with-vscode/https://vitaneri.com/posts/solving-an-import-path-cannot-end-with-a-ts-extension-when-using-deno-with-vscode/A guide on how to eliminate the error message: 'An import path cannot end with a .ts extension' when using Deno with VSCode.Fri, 21 Oct 2022 02:25:04 GMT<p>When we are working with Deno, we often need to import files with .ts extension. But the built-in TS language server from VSCode is usually unhappy when we do this.</p> <p></p> <p><em>An import path cannot end with a '.ts' extension.</em></p> <p>To solve this issue, we need to install the <a href="https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno">official Deno extension for VSCode</a>. This extension is the language server client for Deno.</p> <p>After installing the extension, simply open up your command palette (<code>ctrl</code> + <code>shift</code> + <code>p</code>), and type <code>deno: initialize</code>.</p> <p></p> <p>This will create a <code>.vscode</code> folder in your workspace with a file called <code>settings.json</code> inside. The file will look something like this:</p> <pre><code>{ "deno.enable": true, "deno.lint": true } </code></pre> <p>The <code>deno.enable</code> option will enable the Deno language server and disable the built-in VSCode JavaScript and TypeScript language services.</p> <p>The <code>deno.lint</code> option will enable the deno linter. This option is optional.</p> <p>With that, you should now be able to import a .ts file without any problem.</p> <p>It's also possible to enable the extension globally if you look for <code>Deno: Enable</code> in your VSCode's user setting. But it's not recommended because enabling the Deno language server will disable the built in TS language server. Except if you're sure you'll only be using Deno from now on 😆.</p> denovscodeVincent TaneriSpring Boot: Working With Database Using JDBCTemplatehttps://vitaneri.com/posts/spring-boot-working-with-database-using-jdbctemplate/https://vitaneri.com/posts/spring-boot-working-with-database-using-jdbctemplate/Learn how to connect a Spring Boot application with a relational database using JDBCTemplate.Thu, 01 Sep 2022 01:04:50 GMT<p>In this tutorial, we'll learn how to connect a Spring Boot application with a relational database using JDBCTemplate. First, some background on why JDBCTemplate is used.</p> <h2>Introduction</h2> <p>In the Java world, the tool that's used to integrate a database with the language is called Java Database Connectivity (JDBC). JDBC allows you to connect to a DBMS to work with databases. However, JDBC is very verbose, you have to write a lengthy block of code just to execute a simple SQL query, which is not very comfortable to use. Here is an example:</p> <pre><code>String sql = "INSERT INTO student VALUES (?,?)"; try (PreparedStatement st = con.prepareStatement(sql)) { st.setString(1, name); st.setInt(2, age); st.executeUpdate(); } catch (SQLException e) { // handle exceptions } </code></pre> <p>Spring's JDBCTemplate comes to the rescue. JDBCTemplate reduces the verbosity of plain JDBC considerably, which you will see in the following tutorial.</p> <h2>Creating A CRUD App</h2> <p>In this tutorial, we'll be creating a backend service that exposes 3 endpoints: adding a record to the database, removing a record from the database, and showing all the records in the database.</p> <p>We'll be working with a PostgreSQL database. Inside, there'll be a table called <em>student</em> with 3 columns.</p> <ol> <li>id -- An auto-incrementing integer.</li> <li>name -- The name of the student.</li> <li>age -- The age of the student.</li> </ol> <p><em>Note: the examples in this tutorial will work with any relational database technology you choose with some minor adjustments. I also assume that you have some basic knowledge of Java, Spring Boot, JDBC, and SQL.</em></p> <h4>Generate Spring Boot Project</h4> <p>First, let's use <a href="https://start.spring.io/">Spring Initializr</a> to generate the base for our app. We need to include these dependencies inside the generated <em>pom.xml</em>.</p> <pre><code>&lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-jdbc&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.postgresql&lt;/groupId&gt; &lt;artifactId&gt;postgresql&lt;/artifactId&gt; &lt;scope&gt;runtime&lt;/scope&gt; &lt;/dependency&gt; </code></pre> <p>The last dependency is the JDBC Driver for your chosen database, which is PostgreSQL in this case. Also, the reason we add <code>&lt;scope&gt;runtime&lt;/scope&gt;</code> is because the app only needs the JDBC driver at runtime, it's not needed for compilation.</p> <h3>Configure Database</h3> <p>Next, let's define our table by creating a file in <code>/src/main/resources/</code> called <code>schema.sql</code>.</p> <pre><code>CREATE TABLE IF NOT EXISTS student( id SERIAL PRIMARY KEY, name VARCHAR(50) NOT NULL, age INTEGER NOT NULL ); </code></pre> <p>Next, we have to tell Spring how to connect to our application. We can do this by changing the <code>application.properties</code> file located in <code>/src/main/resources/</code> to look like this:</p> <pre><code>spring.datasource.url=jdbc:postgresql://localhost:5432/test spring.datasource.username=root spring.datasource.password=secret spring.sql.init.mode=always </code></pre> <p>Going from the first line: your connection URL, your DB username, your DB password, and the last line is there to instruct Spring Boot to always run your <code>schema.sql</code> file you defined earlier every time your start the app.</p> <h3>Create Model Class</h3> <p>Now that we're done with the basic configuration for the database, let's start working on our app. First, we'll create a model class called <code>Student</code> that models our table structure.</p> <pre><code>package com.example.model; public class Student { private int id; private String name; private int age; // constructor, getters, and setters } </code></pre> <h3>Create Repository Class</h3> <p>Next, we define <code>StudentRepository</code> which is a bean in the application context that'll be used by our controller to interact with the database.</p> <pre><code>package com.example.repository; @Repository public class StudentRepository { } </code></pre> <p>Since <code>StudentRepository</code> is a bean in the application context, we can inject an instance of <code>JdbcTemplate</code> that we'll use to work with the database.</p> <p>At this point, you must be wondering where the instance of <code>JdbcTemplate</code> is coming from. This is part of Spring Boot's magic. When Spring Boot detects that you have PostgreSQL as a dependency, it automatically configures a <code>DataSource</code> and a <code>JdbcTemplate</code> instance for you.</p> <p>Later in the tutorial, I'll show you how to define your own <code>DataSource</code> and <code>JdbcTemplate</code> instances when you need them.</p> <p>The code block below shows you how to inject the <code>JdbcTemplate</code>.</p> <pre><code>package com.example.repository; @Repository public class StudentRepository { private final JdbcTemplate jdbc; public StudentRepository(JdbcTemplate jdbc) { this.jdbc = jdbc; } } </code></pre> <p>Now that we have the <code>JdbcTemplate</code> instance, we can start working on our CRUD jobs. All we have to do is to pass the SQL and its parameters to a method called <code>update()</code> of the instance. The method abstracts away all the JDBC steps that we have to do.</p> <p>First, let's work on the method to insert and delete a record from the table as they're pretty straightforward. We'll call them <code>addStudent()</code> and <code>deleteStudent</code> respectively.</p> <pre><code>public class StudentRepository { // codes omitted public void addStudent(Student student) { String sql = "INSERT INTO student (name, age) VALUES (?, ?)"; jdbc.update(sql, student.getName(), student.getAge()); } public void deleteStudent(int id) { String sql = "DELETE FROM student WHERE id = ?"; jdbc.update(sql, id); } } </code></pre> <p>See how more succinct it is than working directly with JDBC provided by the JDK.</p> <p>Retrieving data involves more steps, but it's also not that difficult. We'll now work on the method to retrieve all records from the table called <code>findAll()</code>.</p> <pre><code>public class StudentRepository { // codes omitted public List&lt;Student&gt; findAll() { String sql = "SELECT * FROM student"; RowMapper&lt;Student&gt; studentRowMapper = (r, i) -&gt; { int id = r.getInt("id"); String name = r.getString("name"); int age = r.getInt("age"); return new Student(id, name, age); }; return jdbc.query(sql, studentRowMapper); } } </code></pre> <p>Notice that this time we're using <code>jdbc.query()</code> instead of <code>jdbc.update()</code>. The <code>query()</code> method takes two parameters, the SQL command, and a <code>RowMapper</code>. <code>RowMapper</code> is responsible for transforming a row from the <code>ResultSet</code> into a specific object. In this case, the <code>Student</code> object which our app knows how to work with.</p> <h3>Create Controller Class</h3> <p>Now that we are done with our repository object that's in charge of CRUD, the final step is to expose these methods through endpoints. In other words, it's time to implement the controller.</p> <pre><code>package com.example.controller; @RestController @RequestMapping("/student") public class StudentController { private final StudentRepository studentRepository; public StudentController(StudentRepository studentRepository) { this.studentRepository = studentRepository; } @PostMapping public void addStudent(@RequestBody Student student) { studentRepository.addStudent(student); } @DeleteMapping public void deleteStudent(@RequestBody Student student) { studentRepository.deleteStudent(student.getId()); } @GetMapping public List&lt;Student&gt; getAllStudent() { return studentRepository.findAll(); } } </code></pre> <p>We use constructor dependency injection to get the repository object from the Spring context, then we implement the 3 endpoints to execute the CRUDs method from our <code>StudentRepository</code>.</p> <p>In case you are wondering why the GET endpoint knows that <code>List&lt;Student&gt;</code> has to be returned to the client in JSON format, the answer is, again, Spring Boot's magic. By adding the <code>@RestController</code> annotation instead of vanilla <code>@Controller</code>, we don't need to explicitly convert POJO to JSON. Spring Boot will handle it for us.</p> <h2>Wrap Up</h2> <p>And that's it. We're done with the app. You can start the app and test the endpoints using your favorite API testing tools like <em>Postman</em> or <em>cURL</em>.</p> <p><em>Note: when calling the POST and DELETE endpoints, you have to attach a request body containing a JSON that model the <code>Student</code> object and contains an <code>id</code> respectively.</em></p> <p>Here is an example of how the request body should look like when calling the POST endpoint:</p> <pre><code>{ "name": "John", "age": 17 } </code></pre> <p>You can ignore the <em>id</em> field because it's managed by the database as per our schema definition earlier.</p> <p>Here is an example of how the request body should look like when calling the DELETE endpoint:</p> <pre><code>{ "id": 1 } </code></pre> <p>Finally, you can find the source code for this tutorial <a href="https://github.com/tanerijun/jdbctemplate-example">here</a>.</p> <h2>Bonus: Creating Custom Data Source</h2> <p>Spring automatically configures a <code>DataSource</code> bean for you based on the content of your <code>application.properties</code> file. This is what you need most of the time, but there might come a time when you also have to define your own <code>DataSource</code> bean.</p> <p>For example:</p> <ul> <li>Your <code>DataSource</code> implementation might depend on some condition at runtime.</li> <li>You need multiple <code>DataSource</code> instances.</li> <li>You are using vanilla Spring.</li> </ul> <p>To define <code>DataSource</code> yourself, you have to make a custom configuration class. Inside the class, you define a method annotated with <code>@Bean</code>. The <code>DataSource</code> is simply a bean that you can add to the Spring context just like any other bean. Here is an example:</p> <pre><code>@Configuration public class ProjectConfiguration { @Bean public DataSource dataSource() { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl(dataSourceUrl); dataSource.setUsername(dataSourceUsername); dataSource.setPassword(dataSourcePassword); dataSource.setConnectionTimeout(1000); return dataSource; } } </code></pre> <p>I'm using Hikari Connection Pool because it's the default in Spring, but feel free to use any implementation you prefer.</p> javaspringVincent TaneriTest Svelte Component Slot Using svelte-htmhttps://vitaneri.com/posts/test-svelte-component-slot-using-svelte-htm/https://vitaneri.com/posts/test-svelte-component-slot-using-svelte-htm/A guide on how to test Svelte components that have slot using the svelte-htm library.Wed, 01 Mar 2023 16:13:49 GMT<p>This is a short guide on how to test a Svelte component with slot using the <a href="https://github.com/kenoxa/svelte-htm">svelte-htm</a> library.</p> <h2>Introduction</h2> <p>At the time of writing this article, there's no way to pass in slot content to Svelte component using <a href="https://testing-library.com/docs/svelte-testing-library/intro/">svelte-testing-library</a>.</p> <p>The workaround for this is usually by creating a separate dummy component that put some elements inside the slot and test the dummy component instead.</p> <p>For example, say that we have a <code>Button.svelte</code> component.</p> <pre><code>&lt;button&gt; &lt;slot /&gt; &lt;/button&gt; </code></pre> <p>To test if the component inside the slot is rendered properly, we have to create a dummy component that use <code>Button.svelte</code>. We'll call this component <code>TestButton.svelte</code>.</p> <pre><code>&lt;script&gt; import Button from ./Button.svelte; &lt;/script&gt; &lt;Button&gt; &lt;div data-testid="slot-component"&gt;PLACEHOLDER&lt;/div&gt; &lt;/Button&gt; </code></pre> <p>Finally, we can test the component.</p> <pre><code>// Other imports import TestButton from "./TestButton.svelte"; describe("Button", () =&gt; { it("should render component inside slot properly", () =&gt; { render(TestButton); expect(screen.getByTestId("slot-component")).toBeInTheDocument(); }); }); </code></pre> <p>That works, but it's certainly not a fun experience, and your project is probably going to be littered by bunches of dummy component.</p> <h2>Solution</h2> <p>The solution to this problem is to use <code>svelte-htm</code>.</p> <p><code>svelte-htm</code> allows us to write our Svelte components with JSX-like syntax. It completely eliminates our need of dummy component. We can test our Svelte component just like how we test components from JSX-based framework like <a href="https://react.dev/">React</a>.</p> <p>Now, let's refactor our test using <code>svelte-htm</code>.</p> <pre><code>// Other imports import html from `svelte-htm`; import Button from './Button.svelte' describe("Button", () =&gt; { it("should render component inside slot properly", () =&gt; { render(html` &lt;${Button}&gt; &lt;div data-testid="slot-component"&gt;PLACEHOLDER&lt;/div&gt; &lt;/${Button}&gt; `); expect(screen.getByTestId("slot-component")).toBeInTheDocument(); }); }); </code></pre> <p>That's all we need to do. Felt much more natural, right?</p> <p>You might think that the syntax is still not as nice as testing JSX component, but it's pretty close, and I would consider this solution a major leap compared to the dummy component solution.</p> <p>In case you're wondering how the test would look like for JSX component:</p> <pre><code>// Other imports import Button from "./Button.tsx"; describe("Button", () =&gt; { it("should render component inside slot properly", () =&gt; { render( &lt;Button&gt; &lt;div data-testid="slot-component"&gt;PLACEHOLDER&lt;/div&gt; &lt;/Button&gt;, ); expect(screen.getByTestId("slot-component")).toBeInTheDocument(); }); }); </code></pre> <h2>Testing Named Slot</h2> <p>We can test named slot just like how we test normal slot in the examples above.</p> <p>Here is an example:</p> <p>Let's change our <code>Button.svelte</code> component to use named slot.</p> <pre><code>&lt;button&gt; &lt;div&gt; &lt;slot name="icon" /&gt; &lt;/div&gt; &lt;div&gt; &lt;slot name="label" /&gt; &lt;/div&gt; &lt;/button&gt; </code></pre> <p>Now, to test it:</p> <pre><code>// Other imports import html from `svelte-htm`; import Button from './Button.svelte' describe("Button", () =&gt; { it("should render component inside slot properly", () =&gt; { render(html` &lt;${Button}&gt; &lt;div slot="icon"&gt;ICON&lt;/div&gt; &lt;div slot="label"&gt;Click me!&lt;/div&gt; &lt;/${Button}&gt; `); // assertions here ... }); }); </code></pre> <p>You get the idea :)</p> <h2>Wrap Up</h2> <p>That's it for this post. You should be able to test your Svelte components that have slot now. Happy testing!</p> svelteVincent TaneriType Guards In TypeScripthttps://vitaneri.com/posts/type-guards-in-typescript/https://vitaneri.com/posts/type-guards-in-typescript/Exploring type guards in TypeScript.Fri, 14 Oct 2022 02:15:52 GMT<h2>Introduction</h2> <p>When working with union types in TypeScript, we will often come into a situation where we need to use type guard to please the TypeScript compiler. The compiler always apply its strong typing rules to ensure type safety.</p> <p>Take a look at this code:</p> <pre><code>function add(arg1: string | number, arg2: string | number) { return arg1 + arg2; } </code></pre> <p>This is a function that accepts two parameters and returns their sum. The <code>arg1</code> and <code>arg2</code> parameters are union types. They can hold either a string or a number. Unfortunately, when we try to compile this code, we'll get the following error:</p> <pre><code>error TS2365: Operator '+' cannot be applied to types 'string | number' and 'string | number' </code></pre> <p>The compiler is telling us that it cannot tell what type it should use when it attempts to add <code>arg1</code> to <code>arg2</code>. Is it supposed to add number to a string, a string to a number, a string to a string, or a number to a number?</p> <p>In JavaScript, "adding a string and a number" and "adding a number and a number" lead to different results. So the TypeScript compiler won't let us compile before we solve this uncertainties.</p> <p>This is where type guards come in. Type guard performs a check on our type, and then guarantees that type within its scope.</p> <h2>Implementing Type Guard</h2> <p>Let's rewrite our <code>add</code> function to use type guard.</p> <pre><code>function add(arg1: string | number, arg2: string | number) { if (typeof arg1 === "string") { // arg1 is guaranteed to be a string in this scope return arg1 + arg2; } if (typeof arg1 === "number" &amp;&amp; typeof arg2 === "number") { // both arg1 and arg2 are guaranteed to be a number in this scope return arg1 + arg2; } // default: return both as strings return arg1.toString() + arg2.toString(); } </code></pre> <p>The first if statement uses the JavaScript <code>typeof</code> keyword to test <code>arg1</code>'s type. If the type is a string, then the compiler knows that within the code block following it, <code>arg1</code> is definitely a string, and will therefore treat <code>arg1</code> as a string.</p> <p>The second if statement is similar. We have two <code>typeof</code> checks to check whether both <code>arg1</code> and <code>arg2</code> are of type number. If they are both numbers, then the compiler knows that <code>arg1</code> and <code>arg2</code> are definitely of type number within the following code block.</p> <p>Now, let's test the function!</p> <pre><code>console.log(`"1" + "2" = ${add("1", "2")}`); // run first if block console.log(`1 + 2 = ${add(1, 2)}`); // run second if block console.log(`1 + "2" = ${add(1, "2")}`); // run default </code></pre> <p>The results:</p> <pre><code>"1" + "2" = 12 1 + 2 = 3 1 + "2" = 12 </code></pre> <h2>Explanation</h2> <p>We can see that the first call to <code>add</code> is using two arguments that are strings. The code identifies the first argument as being of type string and therefore enters the first if statement block. The concatenation of the string "1" with "2" results in the string "12".</p> <p>The second <code>add</code> uses two numbers as arguments, and our code identifies both arguments as numbers, and as such adds the value 1 and the value 2, resulting in 3.</p> <p>The third <code>add</code> uses a number as the first argument and a string as the second. The code therefore falls through to the default code, treating both arguments as strings.</p> typescriptVincent TaneriType Unknown in TypeScripthttps://vitaneri.com/posts/type-unknown-in-typescript/https://vitaneri.com/posts/type-unknown-in-typescript/Exploring one of the primitive types in TypeScript: Unknown.Fri, 21 Oct 2022 15:06:20 GMT<p>Let's take a look at the <code>unknown</code> type in TypeScript. Type <code>unknown</code> is a very interesting type that only exist in TypeScript. Let's take a look at how it works.</p> <h2>Working With Unknown</h2> <p>I always try to use the <code>unknown</code> type when I need to use <code>any</code>. <code>unknown</code> is like a type-safe version of <code>any</code>.</p> <p>Let's see how it is type-safe by looking at some examples.</p> <pre><code>let a: any = "a string"; let b: number = 0; b = a; </code></pre> <p>This code will work even though the actual type of <code>a</code> is a string because we defined the type to be <code>any</code>. By doing so, TypeScript assumed that we know what we are doing and leave everything in our hands. Which is not good, because as you can see, we just assigned a string to a number. You can see how dangerous the <code>any</code> type is.</p> <p>Let's see how we can make the same code much better using the <code>unknown</code> type.</p> <pre><code>let a: unknown = "a string"; let b: number = 0; b = a; </code></pre> <p>This time, the code won't compile. We'll get a complain from TypeScript instead.</p> <pre><code>Type 'unknown' is not assignable to type 'number' </code></pre> <p>This highlight the differences between the <code>any</code> type and the <code>unknown</code> type. We need to turn the <code>unknown</code> type into a definite type before we can assign it.</p> <p>To assign <code>a</code> to <code>b</code>, TypeScript needs to know for sure that <code>a</code> is of type <code>number</code>. The easiest method to achieve that is by casting the <code>a</code> variable into a <code>number</code>.</p> <pre><code>let a: unknown = "a string"; let b: number = 0; b = &lt;number&gt;a; </code></pre> <p>Or by using type assertion.</p> <pre><code>let a: unknown = "a string"; let b: number = 0; b = a as number; </code></pre> <p>By explicitly casting the <code>unknown</code> type like this, the TS compiler will allow us to assign the value. But as you can see, that's still pretty dangerous. The compiler assumed that we know what we are doing, and leave everything to us just like <code>any</code>.</p> <p>The advantage compared with <code>any</code> is that we need to do explicit casting ourself. This eliminates the chance of accidental assignment.</p> <p>For example: since I know that <code>a</code> is not a number, I should turn <code>a</code> into a number before we assigning it to <code>b</code> to prevent bugs.</p> <pre><code>let a: unknown = "a string"; let b: number = 0; a = 1; b = &lt;number&gt;a; </code></pre> <p>An even safer and more recommended way of dealing with <code>unknown</code> is by narrowing its type using <a href="https://vitaneri.com/posts/type-guards-in-typescript/">type guard</a> just like this.</p> <pre><code>let a: unknown = "a string"; let b: number = 0; if (typeof a === "number") { b = a; } </code></pre> <p>By using a type guard, the TypeScript compiler will know for sure that the variable is of a certain type within the guard block.</p> <h2>Wrap Up</h2> <p>That's it for the <code>unknown</code> type in TypeScript.</p> <p>We should always try to use the <code>unknown</code> type instead of <code>any</code>. The <code>unknown</code> type forces us to double-check before using the variable. We are letting the compiler know what type the value of a variable should be when we need to use it. That's why <code>unknown</code> is considered a type-safe version of <code>any</code>.</p> typescriptVincent TaneriUnderstanding JavaScript Function As First-class Citizenhttps://vitaneri.com/posts/understanding-javascript-function-as-first-class-citizen/https://vitaneri.com/posts/understanding-javascript-function-as-first-class-citizen/A short post explaining the meaning of JavaScript function as a first-class citizen.Fri, 02 Sep 2022 05:15:27 GMT<h2>Introduction</h2> <p>We often hear the phrase "Function is a first-class citizen in JavaScript", but what exactly does it mean?</p> <p>It means that JavaScript <em>function</em> possesses all the capabilities of JavaScript <em>object</em> and is thus treated like any other <em>object</em> in the language. And to be specific:</p> <h3>Function can be created with literals</h3> <pre><code>function() {} </code></pre> <h3>Function can be assigned to variables, array entries, and properties of other objects</h3> <pre><code>const exampleFunction = function () {}; // assigns to a variable exampleArray.push(function () {}); // adds to an array example.data = function () {}; // assigns as a property of another object </code></pre> <h3>Function can be passed as an argument to another <em>function</em></h3> <pre><code>function call(exampleFunction { exampleFunction(); } call(function() {}) </code></pre> <h3>Function can be returned from another <em>function</em></h3> <pre><code>function exampleFunction() { return function () {}; } </code></pre> <h3>Function can be assigned properties</h3> <pre><code>const exampleFunction = function () {}; exampleFunction.name = "Example"; </code></pre> <h2>Wrap Up</h2> <p>Whatever we can do with <em>object</em> in JavaScript, we can also do with <em>function</em>. <em>Function</em> is the same as <em>object</em>, but with an additional, special capability of being <em>invokable</em>. That is, <em>function</em> can be called or invoked in order to perform an action.</p> javascriptVincent TaneriUnderstanding Mapped Types In TypeScripthttps://vitaneri.com/posts/understanding-mapped-types-in-typescript/https://vitaneri.com/posts/understanding-mapped-types-in-typescript/Exploring Mapped Types in TypeScript.Sat, 29 Oct 2022 04:53:41 GMT<p>In this post, we'll look at Mapped Types in TypeScript.</p> <p>It's recommended that you have a basic understanding of <a href="introduction-to-generics-in-typescript">generics</a> first before proceeding.</p> <h2>What Is Mapped Type?</h2> <p>A mapped type is a generic type which uses a union of PropertyKeys (frequently created via <code>keyof</code>) to iterate through keys to create a new type.</p> <p>Mapped type is easier to explain using examples. Say that we have an interface that look like this:</p> <pre><code>interface RequireAB { a: number; b: string; } </code></pre> <p>Any object that implements the interface must have the <code>a</code> and <code>b</code> properties.</p> <pre><code>const obj: RequireAB = { a: 1, b: "hello", }; </code></pre> <p>Now, what if we want to make another interface that doesn't require the <code>a</code> and <code>b</code> properties. We can accomplish it this way.</p> <pre><code>interface NotRequireAB { a?: number; b?: string; } </code></pre> <p>This look awfully familiar with the <code>RequireAB</code> interface above. Can't we just create our <code>NotRequireAB</code> based on <code>RequireAB</code>? Of course we can, using Mapped Type.</p> <pre><code>interface RequireAB { a: number; b: string; } const obj: RequireAB = { a: 1, b: "hello", }; type NotRequireAB&lt;RequireAB&gt; = { [K in keyof RequireAB]?: RequireAB[K]; }; const obj2: NotRequireAB&lt;RequireAB&gt; = {}; </code></pre> <p>We created <code>NotRequireAB</code> based on <code>RequireAB</code>. The type will contain a property for each property in <code>RequireAB</code> but with an optional modifier (<code>?</code>) next to it. We're basically just creating this code dynamically:</p> <pre><code>type NotRequireAB = { a?: number; b?: string; }; </code></pre> <p>An advantage of using this method to hard-coding is that we don't need to maintain 2 separate types. In the case where we have to add some more properties to <code>RequireAB</code>, we don't need to do it for <code>NotRequireAB</code> if we created it using mapped type. This will make the code more maintainable.</p> <pre><code>interface RequireAB { a: number; b: string; c: boolean; d: string | number; } // We don't need to do any modification here type NotRequireAB&lt;RequireAB&gt; = { [K in keyof RequireAB]?: RequireAB[K]; }; </code></pre> <p>We can make the type even more powerful with generics.</p> <pre><code>type WeakInterface&lt;T&gt; = { [K in keyof T]?: T[K]; }; </code></pre> <p>WeakInterface is a type that take in a type <code>T</code> and make all the properties optional.</p> <p>We can use <code>WeakInterface</code> whenever we need to use an interface but with all the properties optional.</p> <pre><code>const optional: WeakInterface&lt;RequireAB&gt; = {}; </code></pre> <p>Note that we still can't define properties that are not available on the original type.</p> <pre><code>const willError: WeakInterface&lt;RequireAB&gt; = { c: "test"; } </code></pre> <p>The code above will produce the following error:</p> <pre><code>Type '{ c: string; }' is not assignable to type 'WeakInterface&lt;RequireAB&gt;'. Object literal may only specify known properties, and 'c' does not exist in type 'WeakInterface&lt;RequireAB&gt;'. </code></pre> <h2>Adding And Removing Modifiers</h2> <p>We can add or remove modifiers by prefixing them using the <code>+</code> or <code>-</code> operator.</p> <p>When no operator is specified, TypeScript will assume that it's <code>+</code>. That's why on our <code>WeakInterface</code> above, we don't need to specify <code>+</code> before our <code>?</code> modifier.</p> <p>Now let's look at an example where we use the <code>-</code> operator. Say that we want to make our <code>WeakInterface</code> strong again. We can remove all the <code>?</code> modifier like this:</p> <pre><code>type StrongInterface&lt;T&gt; = { [K in keyof T]-?: T[K]; }; </code></pre> <p>All we have to do is add the <code>-</code> operator before the modifier.</p> <h2>Introducing Some Predefined Mapped Types</h2> <p>Transforming properties with mapped types is a very common operations that TypeScript provides us with some predefined type definitions.</p> <p>You can check them out on <a href="https://github.com/microsoft/TypeScript/blob/main/lib/lib.es5.d.ts">lib.es5.d.ts</a>.</p> <p>In this section, we'll explore some of these type definitions.</p> <h3>Partial</h3> <p>Partial make all properties of a type optional.</p> <pre><code>/** * Make all properties in T optional */ type Partial&lt;T&gt; = { [P in keyof T]?: T[P]; }; </code></pre> <p>Our <code>WeakInterface</code> we implemented before is actually a Partial.</p> <h3>Required</h3> <p>Required is the opposite of Partial. It will mark each property as required.</p> <pre><code>/** * Make all properties in T required */ type Required&lt;T&gt; = { [P in keyof T]-?: T[P]; }; </code></pre> <h3>Readonly</h3> <p>We can use Readonly mapped type to mark each property as readonly (immutable), as follows:</p> <pre><code>/** * Make all properties in T readonly */ type Readonly&lt;T&gt; = { readonly [P in keyof T]: T[P]; }; </code></pre> <p>Readonly is a mapped type that adds a <code>readonly</code> property to each properties of the type, making the type immutable.</p> <p>We can also create a type that remove the <code>readonly</code> modifier, and make the properties mutable again.</p> <pre><code>type CreateMutable&lt;T&gt; = { -readonly [K in keyof T]: T[K]; }; </code></pre> <p>Now, Let's look at an example of using Readonly.</p> <pre><code>interface RequireAB { a: number; b: string; } const obj: Readonly&lt;RequireAB&gt; = { a: 1, b: "hello", }; obj.a = 2; </code></pre> <p>The last line will produce an error as expected.</p> <pre><code>Cannot assign to 'a' because it is a read-only property. </code></pre> <h3>Pick</h3> <p>Pick is used to construct a type based on a subset of properties of another type.</p> <pre><code>/** * From T, pick a set of properties whose keys are in the union K */ type Pick&lt;T, K extends keyof T&gt; = { [P in K]: T[P]; }; </code></pre> <p>Let's look at an example that use Pick.</p> <pre><code>interface ABC { a: number; b: string; c: boolean; } let obj: Pick&lt;ABC, "a" | "b"&gt; = { a: 1, b: "hello", }; </code></pre> <p>In <code>obj</code>, we only need to specify the properties <code>a</code> and <code>b</code>. Property <code>c</code> doesn't exist on the type generated by Pick.</p> <h3>Record</h3> <p>Record is used to construct a type on the fly. In a way, it's the opposite of Pick. Record uses a list of properties as a string literal to define what properties the type must have.</p> <pre><code>/** * Construct a type with a set of properties K of type T */ type Record&lt;K extends keyof any, T&gt; = { [P in K]: T; }; </code></pre> <p>Let's look at an example that use Record.</p> <pre><code>let obj: Record&lt;"c" | "d", string&gt; = { c: "hello", d: "world", }; </code></pre> <p>The type in our <code>obj</code> is created by passing two generic arguments to the Record type. Record then create a new type with the properties of <code>c</code> and <code>d</code>, both of type string.</p> <h2>Wrap Up</h2> <p>That's it for Mapped Types 🎉. Hope you find it useful.</p> typescriptVincent TaneriUnderstanding Space Complexity Of Algorithmhttps://vitaneri.com/posts/understanding-space-complexity-of-algorithm/https://vitaneri.com/posts/understanding-space-complexity-of-algorithm/A guide on calculating the space complexity of algorithms.Mon, 10 Oct 2022 02:34:04 GMT<p>If you're like me, you'll find space complexity much more tricky to calculate than the time complexity. It always seems to go over your head.</p> <p>In this post, we'll learn about space complexity by looking at several examples. We'll also learn that there are 2 ways to look at space complexity.</p> <h2>What Is Space Complexity?</h2> <p>Space complexity refers to how much memory required by an algorithm grows with respect to the size of the input given to the algorithm.</p> <p>For example, if we have a function <code>doSomething(n)</code>. Space complexity refers to how much space <code>doSomething(n)</code> will occupy in memory based on the size of <code>n</code>.</p> <p>Just like time complexity, space complexity is often expressed with the big O notation, such as <code>O(1)</code>, <code>O(n)</code>, <code>O(n log(n)</code>, etc.</p> <p>Before we dive into the examples, there's another concept that we need to understand, and that is <strong>auxiliary space</strong>.</p> <p>Auxiliary space is the extra space used by an algorithm (excluding the input).</p> <p>When it comes to calculating space complexity as a whole, we need to include both auxiliary space and the space used by the input.</p> <p>Space complexity = Auxiliary Space + Space taken by input values.</p> <p>However, sometimes we don't consider this as the actual measure of space complexity. Sometimes we only consider the auxiliary space.</p> <p>For example, if we want to compare standard sorting algorithms on the based on space, then auxiliary space would be a better criterion than space complexity. Merge Sort uses <code>O(n)</code> auxiliary space, Insertion sort, and Heap Sort use <code>O(1)</code> auxiliary space. The space complexity of all these sorting algorithms is <code>O(n)</code> though.</p> <p><em>More about this on example 3 later.</em></p> <h2>Examples</h2> <p>Let's dive into some examples to finally make sense of space complexity!</p> <h3>Example 1</h3> <p>Let's start by taking a look at this simple algorithm that adds two numbers.</p> <pre><code>int addTwoNumbers(int n1, int n2) { int sum = n1 + n2; return sum; } </code></pre> <p>Let's try estimating the size that'll be used by the function!</p> <p>Assuming that an integer take 4 bytes, and the auxiliary space is also 4 bytes.</p> <p><em>The auxiliary space here refers too stuff like the function call, the return call, how to do a loop, etc. (Basically the computer instructions).</em></p> <p>To the calculation:</p> <p><code>space complexity = sizeof n1 + sizeof n2 + sizeof sum + auxiliary space = 16 bytes.</code></p> <p>For this kind of algorithm, no matter what the values of <code>n1</code> and <code>n2</code> are, the space needed is always the same. Everything inside the algorithm is of a fixed size. This is also called <strong>constant</strong> space complexity or <code>O(1)</code>.</p> <p></p> <h3>Example 2</h3> <p>Let's take a look at another example!</p> <p>This is an algorithm to sum all the numbers in an array.</p> <pre><code>int sumNumbersInArray(int[] arr) { int sum = 0; for (int i = 0; i &lt; arr.length; i++) { sum += arr[i]; } return sum; } </code></pre> <p>Unlike the first example, this time the size of arr is dynamic. Let's call it <code>n</code>.</p> <p>Assuming that the size of an integer is 4 bytes, and the auxiliary space is also 4 bytes. The total space needed is:</p> <p><code>space complexity = sizeof arr + sizeof sum + sizeof i + auxiliary space = 4n + 12 bytes</code></p> <p>or</p> <p><code>space complexity = O(4n + 12 bytes)</code></p> <blockquote> <p>Remember that constants are ignored in Big O Notation.</p> </blockquote> <p>So the space complexity is <code>O(n)</code>, also called <strong>linear</strong> space complexity.</p> <p></p> <h3>Example 3</h3> <p>Earlier I mentioned that sometimes we only consider the auxiliary space when calculating space complexity.</p> <p>This example will make it clear why we do that.</p> <p>In this example, we'll look at 2 versions of an algorithm to count the <a href="https://en.wikipedia.org/wiki/Factorial">factorial</a> of a number. One is iterative, while the other one is recursive.</p> <p>Let's start with the iterative version:</p> <pre><code>int factorial(int n) { int result = 1; for (int i = 1; i &lt;= n; i++) { result = result * i } return result; } </code></pre> <p>Assuming that the size of an integer is 4 bytes and the auxiliary space is 4 bytes. The space complexity for this algorithm is:</p> <p><code>space complexity = sizeof n + sizeof result + sizeof i + auxiliary space = 16 bytes</code></p> <p>Removing the constants, our space complexity is constant (<code>O(1)</code>).</p> <p>No matter what <code>n</code> we pass to the function, no matter how many times the loop run, the space complexity will be the same (there's just one variable <code>i</code>).</p> <p>Now, let's look at the recursive version!</p> <pre><code>int factorial(n) { if (n &lt;= 1) { return 1; } return n * factorial(n - 1); } </code></pre> <p>This time, we're down to only 1 variable (<code>n</code>). But the auxiliary space needed is not as simple anymore.</p> <p>Let's look at the call stack assuming <code>n = 5</code>.</p> <p></p> <p>As the value of <code>n</code> increases, the number of function call also increase. Each function call has each own auxiliary space. So the auxiliary space will be based on <code>n</code>.</p> <p>Going back to the algorithm, the space complexity for the algorithm is:</p> <p><code>space complexity = sizeof n + (n * auxiliary space)</code></p> <p>Remove the constants, and we get:</p> <p><code>space complexity = O(n)</code></p> <p>In a recursive algorithm like this, auxiliary space is no longer just a constant. It is the focus of the calculation instead.</p> <p>This is why merge sort's space complexity is <code>O(n)</code> while insertion sort's space complexity is only <code>O(1)</code>.</p> <h2>Wrap Up</h2> <p>That's it for space complexity 🎉.</p> <p>I hope this article give you a better understanding of space complexity, especially when deciding whether or not you have to factor in the auxiliary space into the calculation.</p> dsaVincent TaneriUse Configurations From Tailwind In Vanilla CSShttps://vitaneri.com/posts/use-configurations-from-tailwind-in-vanilla-css/https://vitaneri.com/posts/use-configurations-from-tailwind-in-vanilla-css/A guide on how to use Tailwind's configuration (like colors, spacing, etc.) in vanilla CSS.Tue, 22 Aug 2023 01:55:58 GMT<p>You might have been in a situation where you're forced or would prefer to write vanilla CSS in a Tailwind project.</p> <p>In my case, I wanted to write some animation code involving multiple keyframes, and pseudo-elements, and implementing it in Tailwind resulted in a class name that's very long and hard to read, so I reached out to vanilla CSS instead.</p> <p>That's when I ran into a problem. I also wanted to use colors and spacing from my Tailwind configs. For example, instead of hard coding the red color <code>#dc2626</code> in my CSS file, I wished I can use Tailwind's <code>bg-red-600</code>. And fortunately, there's a solution.</p> <h2>theme()</h2> <p>To solve this issue, we can use the <code>theme()</code> utility function from Tailwind. There's no need to import or configure anything, just use it directly in your CSS file.</p> <p>Examples:</p> <pre><code>button { background: theme(colors.red.600); color: theme(colors.red.100); padding: theme(spacing.4); } </code></pre> <p>You can also use it for CSS variable like this:</p> <pre><code>:root { --dark: theme(colors.zinc.900); --dark-shade: theme(colors.zinc.600); --light: theme(colors.white); --light-shade: theme(colors.zinc.400); } </code></pre> <blockquote> <p>Tips: If you use <a href="https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss">Tailwind's Intellisense</a>, you'll also get auto complete inside <code>theme()</code>.</p> </blockquote> <h2>How It Works</h2> <p>So how does it work?</p> <p>On build time, Tailwind will replace all the <code>theme()</code> calls with static value.</p> <h2>Wrap Up</h2> <p>That's it for this post. Hope you find it useful.</p> <p>One final thing, this trick not only works in Vanilla CSS but also in scoped CSS in frontend frameworks like Vue, Svelte, Astro, etc.</p> cssVincent TaneriWeb Scraping On The Edge Using HTMLRewriterhttps://vitaneri.com/posts/web-scraping-on-the-edge-using-htmlrewriter/https://vitaneri.com/posts/web-scraping-on-the-edge-using-htmlrewriter/A guide on doing light web scraping on edge environments like Cloudflare Worker using HTMLRewriter.Sat, 19 Aug 2023 12:44:35 GMT<p>In this tutorial, we're going to create a web scraper using HTMLRewriter. Specifically, we're going to create a web service that scrape what a user is currently reading on <a href="https://www.goodreads.com/">Goodreads</a> served as JSON data.</p> <h2>Technologies</h2> <p>First, a short introduction to the techs we're going to use.</p> <h4>HTMLRewriter</h4> <p>As the name suggest, HTMLRewriter is a super lightweight and fast tool to rewrite HTML created for the edge environment like <a href="https://workers.cloudflare.com/">Cloudflare Workers</a>, <a href="https://deno.land/">Deno</a>, and <a href="https://bun.sh/">Bun</a>.</p> <p>Even if it's main purpose is to rewrite HTML, we can also use it to parse HTML, because it can't rewrite HTML without parsing it first.</p> <p>It might not be ideal for large scale scraping though (which you'll see in the examples later on), but for our purpose, it's more than enough.</p> <p>If you're interested with HTMLRewriter, you can read more about the history of its creation on <a href="https://blog.cloudflare.com/html-parsing-1/">Cloudflare's blog</a>.</p> <h4>Hono</h4> <p><a href="https://hono.dev/">Hono</a> is a small, simple, and ultrafast web framework designed for the edge. We're going to use Hono as our router.</p> <h4>Cloudflare Workers</h4> <p>The app will be deployed as a <a href="https://workers.cloudflare.com/">Cloudflare Worker</a> running on the edge (close to your users).</p> <blockquote> <p>Note that even though, We're deploying to Cloudflare Worker in this tutorial, the tutorial should also apply for other environments that implement HTMLRewriter like <a href="https://deno.land/x/html_rewriter">Deno</a> and <a href="https://bun.sh/docs/api/html-rewriter">Bun</a>.</p> </blockquote> <h2>Building The Scraper</h2> <p>Let's begin building our app.</p> <blockquote> <p>For those that prefer to just read the code, the source code is open sourced on <a href="https://github.com/tanerijun/goodreads-currently-reading">Github</a>.</p> </blockquote> <h3>Setup</h3> <p>Let's begin by scaffholding our project using the Cloudflare Workers template from Hono.</p> <pre><code>npm create hono@latest my-app </code></pre> <p>Then select Cloudflare Workers (<em>Arrow key to move, and Space key to select</em>) in the provided options.</p> <p>Make sure to install the dependencies by running:</p> <pre><code>npm install </code></pre> <p>And you should now be able to start the dev server by running:</p> <pre><code>npm run dev </code></pre> <p>Now, if you go to the provided link, default to <code>http://127.0.0.1:8787/</code>, you should see the text <code>Hello Hono!</code>.</p> <h3>File structure</h3> <p>The generated file structure is really simple. Other than the standard npm stuff, the one that you might not be familiar with if you've never build a Cloudflare Worker before is <code>wrangler.toml</code>.</p> <p>The file contains metadata and configurations for the project. For example: your <code>Worker KV</code>, <code>D1</code>, etc.</p> <p>In this project though, we're not going to need any of that. But you can change the <code>name</code> to the name of your app. Cloudflare will use the <code>name</code> as part of your deployed app's URL, and also as an identifier in Cloudflare's dashboard.</p> <p>I'm going to name mine: <code>goodreads-currently-reading</code></p> <pre><code>name = "goodreads-currently-reading" compatibility_date = "2023-01-01" </code></pre> <p>Alright, now that we're done here. Let's explore <code>src/index.ts</code>, where we're going to spend our time in, for the rest of the tutorial.</p> <h3>Routing</h3> <p>Now, if you open the file, you should be greeted with code similar to this:</p> <pre><code>import { Hono } from "hono"; const app = new Hono(); app.get("/", (c) =&gt; c.text("Hello Hono!")); export default app; </code></pre> <p>The code should be really familiar if you have experience with backend frameworks like <a href="https://expressjs.com/">Express</a>.</p> <p>Our app will only have 1 route, <code>/:id</code>. The <code>id</code> here refers to Goodreads' user id. To create the route, just add the following code after the <code>index</code> route handler:</p> <pre><code>import { Hono } from "hono"; const app = new Hono(); app.get("/", (c) =&gt; c.text("Hello Hono!")); app.get("/:id", async (c) =&gt; { const id = c.req.param("id"); return c.json({ userId: id }); }); export default app; </code></pre> <p>Verify that your app is working by going to <code>/&lt;anything&gt;</code>.</p> <p>You should get a JSON response like this.</p> <pre><code>{ userId: 123; } </code></pre> <h3>Fetching</h3> <p>Now that we have the user ID, we need to use it to fetch the "currently-reading" page of the user from Goodreads.</p> <p>In case you don't know, you can get your Goodreads' user ID by going to your profile page in Goodreads. And it's there in the URL. For example, here is mine:</p> <pre><code>https://www.goodreads.com/user/show/74091755-tvince </code></pre> <p>We only need the <code>id</code> number (<code>74091755</code>). So feel free to omit the following <code>username</code>.</p> <p>Going back to the code, here is how you can fetch the "currently-reading" page:</p> <pre><code>app.get("/:id", async (c) =&gt; { const id = c.req.param("id"); const response = await fetch(`https://www.goodreads.com/review/list/${id}?shelf=currently-reading`); return c.json({ userId: id }); }); </code></pre> <blockquote> <p>Tips: You can also fetch other shelves by modifying <code>shelf=currently-reading</code>. For example: <code>shelf=read</code>.</p> </blockquote> <p>Let's also do a minimal error handling in case the fetch request fails.</p> <pre><code>app.get("/:id", async (c) =&gt; { const id = c.req.param("id"); const response = await fetch(`https://www.goodreads.com/review/list/${id}?shelf=currently-reading`); if (!response.ok) throw new HTTPException(response.status, { message: response.statusText }); return c.json({ userId: id }); }); </code></pre> <h3>Scraping</h3> <p>Now, that we're connected with Goodreads. We can start scraping.</p> <p>To start scraping, we have to pass <code>response</code> to HTMLRewriter to parse and transform. But since we don't need the result of the transformation, we can just ignore it.</p> <pre><code>app.get("/:id", async (c) =&gt; { // Fetch Goodreads with userId... // Array to store our data const res: { title: string; url: string }[] = []; await new HTMLRewriter() .on("td.field.title a", { element(el) { const title = el.getAttribute("title"); const url = el.getAttribute("href"); if (title &amp;&amp; url) { res.push({ title, url }); } }, }) .transform(response) .arrayBuffer(); // drive the parser return c.json(res); // return the array as JSON }); </code></pre> <p>We created an array to store our data, then we pass the response to the HTMLRewriter instance.</p> <p>The interesting and most important bit here is the <code>.on</code> method. Its first argument is a <a href="https://developers.cloudflare.com/workers/runtime-apis/html-rewriter/#selectors">selector</a>, and its second argument is an instance of <a href="https://developers.cloudflare.com/workers/runtime-apis/html-rewriter/#element-handlers">ElementHandler</a>.</p> <p>The <code>ElementHandler</code> looks like this in full:</p> <pre><code>class ElementHandler { element(element) { // An incoming element } comments(comment) { // An incoming comment } text(text) { // An incoming piece of text } } </code></pre> <p>In the case of our app, our selector captured an HTML tree that look like this:</p> <pre><code>&lt;a title="Pixel Art for Game Developers" href="/book/show/26117789-pixel-art-for-game-developers"&gt; Pixel Art for Game Developers &lt;/a&gt; </code></pre> <p>Now, if this tree is passed to <code>ElementHandler</code>:</p> <p>Then <code>element</code> refers to the <code>&lt;a&gt;</code> tag, while the <code>text</code> refers to the text inside ("Pixel Art for Game Developers"), and <code>comment</code> is <code>undefined</code> in this case, since there's no HTML comment.</p> <p>Now, back to our app.</p> <p>Since the data that I needed is conveniently provided in the <code>&lt;a&gt;</code> element, I can just take it using the <code>getAttribute</code> method and push it into the array.</p> <pre><code>element(el) { const title = el.getAttribute("title"); const url = el.getAttribute("href"); // Type guard to make Typescript happy if (title &amp;&amp; url) { res.push({ title, url }); } }, </code></pre> <p>Now if you run the app, go to <code>/:id</code>, and check the result, you should get the data as intended.</p> <pre><code>[ { "title": "さくら荘のペットな彼女", "url": "/book/show/16088343" }, { "title": "Thinking, Fast and Slow", "url": "/book/show/11468377-thinking-fast-and-slow" } ] </code></pre> <h3>Finalizing</h3> <p>That's it for our app. We achieved our objective. Here is the code in full.</p> <pre><code>import { Hono } from "hono"; import { HTTPException } from "hono/http-exception"; const BASE_URL = "https://goodreads.com"; const app = new Hono(); app.get("/", (c) =&gt; c.text("Hello Hono!")); app.get("/:id", async (c) =&gt; { const id = c.req.param("id"); const response = await fetch(`${BASE_URL}/review/list/${id}?shelf=currently-reading`); if (!response.ok) throw new HTTPException(response.status, { message: response.statusText }); const res: { title: string; url: string }[] = []; await new HTMLRewriter() .on("td.field.title a", { element(el) { const title = el.getAttribute("title"); const url = el.getAttribute("href"); if (title &amp;&amp; url) { res.push({ title, url: BASE_URL + url }); } }, }) .transform(response) .arrayBuffer(); return c.json(res); }); export default app; </code></pre> <p>Notice that I refactored the app a bit because the <code>href</code> attribute of the <code>&lt;a&gt;</code> is relative, but I want it to be an absolute URL. So, I extracted the Goodreads url into a separate variable.</p> <p>You should also adjust yours to better fit your needs. Maybe you also want to scrape the cover? the rating? You got the idea.</p> <h3>Deploying</h3> <p>Finally, you can deploy your app using the command:</p> <pre><code>npm run deploy </code></pre> <p>You might be prompted to sign in if it's your first time using Wrangler. Simply follow the instructions.</p> <p>Wrangler should start deploying your project, and you should get a live URL to your app. Congrats!</p> <h2>Bonus</h2> <p>I hope that by now you have a pretty a good idea of how to use HTMLRewriter for web scraping. As a bonus content, I want to address some common gotchas when using HTMLRewriter for web scraping.</p> <h3>Text Content Might Come In Chunk</h3> <p>Say that we have an HTML that look like this:</p> <pre><code>&lt;p&gt;Hello, world!&lt;/p&gt; </code></pre> <p>When you access the text using HTMLRewriter, it might come in chunks like: <code>He</code>, <code>llo, </code>, <code>world</code>, <code>!</code>.</p> <p>So, always remember to concatenate these chunks when scraping for text data.</p> <p>You'll see an example in the next section.</p> <h3>Can't Directly Access Nested Element</h3> <p>At the time of writing, The <a href="https://developers.cloudflare.com/workers/runtime-apis/html-rewriter/#element">Element</a> object doesn't have any method to directly access nested elements. So, in order to access nested elements, we have to run separate selectors and handlers for them.</p> <p>For example, say that our HTML look like this:</p> <pre><code>&lt;a href="/A" title="A"&gt; &lt;img src="https://link-to-foo.png" /&gt; &lt;span class="caption"&gt;Foo&lt;/span&gt; &lt;/a&gt; &lt;a href="/B" title="B"&gt; &lt;img src="https://link-to-bar.png" /&gt; &lt;span class="caption"&gt;Bar&lt;/span&gt; &lt;/a&gt; </code></pre> <p>And we want our data to be in this shape:</p> <pre><code>type Item = { title: string | null; url: string | null; img: string | null; caption: string | null; }; </code></pre> <p>When we're on the <code>a</code> selector, we have no way to access the nested <code>&lt;img /&gt;</code> and <code>&lt;span&gt;</code> inside it. To access them, we need to create separate selectors to handle each case.</p> <p>Like this:</p> <pre><code>const item: Item = { title: null, url: null, string: null, caption: null }; await new HTMLRewriter() .on("a", { element(el) { item.title = el.getAttribute("title"); item.url = el.getAttribute("href"); }, }) // Separate selector for nested element .on("a img", { element(el) { item.img = el.getAttribute("src"); }, }) // Separate selector for nested element .on("a .caption", { text({ text }) { // Handle null because initial value is null if (item.caption === null) { item.caption = text; return; } // String concatenation because text might come in chunks item.caption += text; }, }) .transform(response) .arrayBuffer(); </code></pre> <p>And it can get a little complicated when we need to scrape multiple items.</p> <pre><code>// Array to store the results const items: Item[] = []; await new HTMLRewriter() .on("a", { element(el) { // This selector is the start of a new Item object const item: Item = { title: null, url: null, img: null, caption: null }; item.title = el.getAttribute("title"); item.url = el.getAttribute("href"); items.push(item); }, }) // Separate selector for nested element .on("a img", { element(el) { // Access the latest item added by the parent's handler const lastItem = items[items.length - 1]; lastItem.img = el.getAttribute("src"); }, }) // Separate selector for nested element .on("a .caption", { text({ text }) { const lastItem = items[items.length - 1]; // Handle null because initial value is null if (lastItem.caption === null) { lastItem.caption = text; return; } // String concatenation because text might come in chunks items[items.length - 1].caption += text; }, }) .transform(response) .arrayBuffer(); </code></pre> <p>Fortunately, as you might have noticed, our handlers are called in order, allowing the code above to work.</p> <h2>Wrap Up</h2> <p>That's it! Hope you find the tutorial useful. And if you need it, the source code for <code>goodreads-currently-reading</code> is on my <a href="https://github.com/tanerijun/goodreads-currently-reading">Github</a>.</p> typescriptcloudflarehonoVincent Taneri