Nono.MA

FEBRUARY 8, 2024

You can directly assign new properties.

(window as any).talk = () => { console.log(`Hello!`) }

You can extend the Window interface with typings and then assign the property values.

declare global {
  interface Window {
    talk: () => void
    concat: (words: string[]) => string
  }
}

window.talk = () => { console.log(`Hello!`) }
window.concat = (words: string[]) => {
  return words.join(`, `)
}

SEPTEMBER 27, 2023

Say we have a TypeScript interface with required and optional values.

interface NonosOptions {
  thickness: number,
  pressure?: number
}

thickness is required, pressure is optional.

If we create an object of type NonosOptions, we can omit pressure but not thickness.

const options: NonosOptions = {
  thickness: 1.5
}

We can now deconstruct our options with a default pressure value, which will only be used if options doesn't define a value.

const { thickness = 2, pressure = 0.75 } = options
// thickness = 1.5
// pressure = 0.75

As you can see, thickness ignores the 2 assignment because options sets it as 1.5. But pressure is set to 0.75 because options doesn't define a pressure value.

If pressure is defined in options, both thickness and pressure deconstruction fallback values would be ignored.

const options: NonosOptions = {
  thickness: 1.5,
  pressure: 0.25
}

const { thickness = 2, pressure = 0.75 } = options
// thickness = 1.5
// pressure = 0.25

JULY 19, 2023

Even though Vite doesn't like chunks larger than 500 kBs after minification, you can increase the kB limit. Remember, this is just a warning, not an error.

An alternative solution is to chunk your JavaScript bundle into separate chunks, known as chunking. You can do this with the vite-plugin-chunk-split package.

JUNE 2, 2023

I've been doing a lot of React and TypeScript work lately. It had been a few years since I worked with them on a daily basis, and things are improving a lot. It's a breeze to work with some of these technologies to build web apps, and one of the newest additions that works well is Vite.

Is anyone else working with React these days? I will cover some of my learnings on YouTube and want to get a sense of interest. (Let me know on Discord.)

What's cool is that frameworks such as ONNX and TensorFlow have wide support to export and run models in the browser (web workers, WebGPU, WebAssembly) and you don't even need to build microservices for certain models. (Plus there's now support for Node.js to run in the browser as well!)

APRIL 13, 2023

Here are three ways to define a React component in TypeScript which, in the end, are three ways to define a function in TypeScript—React components are JavaScript functions.

const MyComponent = (text: string) => <>{text}</>
const MyComponent = (text: string) => {
  return (
    <>{text}</>
  )
}
function MyComponent(text: string) {
  return <>{text}</>
}

FEBRUARY 24, 2023

Here's how to define simple async functions in TypeScript.

(async (/*arguments*/) => {/*function logic*/})(/*values*/); 

No arguments

// Define an asynchronous function.
const helloAsync = async() => { console.log("Hey, Async!"); }

// Call it asynchronously.
helloAsync();

With arguments

(async(text: string) => { console.log(text); })("Hello, Async!")

With delay

(async(text: string) => { setTimeout(() => console.log(text), 2000); })("Hello, Async!")

Synchronously inside of an asynchronous function

// Say we have an async talk() function that logs text to the console.
const talk = async(text: string) => { console.log(text); }

// And a sleep() function that uses a Promise to wait for milliseconds.
const sleep = (ms: number) => {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// We can wrap calls to async functions in an async function.
// Then `await` to execute them synchronously.
(async () => {
  await talk(`Hello!`);
  await sleep(1000);
  await talk(`What's up?`);
  await sleep(2000);
  await talk(`Bye now!`);
})();

NOVEMBER 2, 2022

You can get tomorrow's date in TypeScript with the Date class.

// Create a date
const tomorrow = new Date()

// Set date to current date plus 1 day
tomorrow.setDate(tomorrow.getDate() + 1)
// 2022-11-03T09:55:29.395Z

You could change that + 1 to the time delta you want to go backward or into the future.

// Create a date for Jan 2, 2020
const aDate = new Date(Date.parse("2020-01-02"))

// Go back in time three days
aDate.setDate(aDate.getDate() - 3)
new Date(aDate)
// 2019-12-30T00:00:00.000Z

// Go back in time three days
aDate.setDate(aDate.getDate() - 3)
new Date(aDate)
// 2019-12-27T00:00:00.000Z

// Go forward in time forty days
aDate.setDate(aDate.getDate() + 40)
new Date(aDate)
2020-02-05T00:00:00.000Z

OCTOBER 28, 2022


How to build a website with the Next.js React framework and TypeScript.

# TL;DR
npx create-next-app@latest --ts
cd my-app
npm run build
npm start
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000

See transcript ›

SEPTEMBER 5, 2022

Here's how to round a decimal float number to two decimals in TypeScript.

parseFloat("123.456").toFixed(2);
// Returns 123.46

Of course, you could change toFixed(2) to any number to keep as many decimals as you wanted.

AUGUST 8, 2022


How to build a client for real-time communication with WebSockets in TypeScript using the ws NPM package.


See transcript ›

AUGUST 1, 2022


How to build a server for real-time communication with WebSockets in TypeScript using the ws NPM package.


See transcript ›

JULY 25, 2022


WebSocket server and client in TypeScript & Node.js with the ws NPM package.


See transcript ›

JULY 18, 2022


How to download Elgato Stream Deck's software, assign actions to keys & the Store.


See transcript ›

JULY 2, 2022

Here is the fastest way to create a Next.js React app with TypeScript. For the step-by-step version, take a look at the longer version.

Create a Next.js App with TypeScript

Let's use npx and create-next-app.

npx \
create-next-app nextjs-app \
--use-npm \
--example \
"https://github.com/nonoesp/next-learn/tree/master/basics/typescript-final"

Run the app in development mode

# Enter the app's directory
cd nextjs-app
# Run the app in development
npm run dev
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000

You should be able to access the site at http://localhost:3000.

Build & Run for Production

npm run build
npm start
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000

Hands-on tutorial

You can watch my step-by-step video on How to build a Next.js app with React & TypeScript.

JUNE 18, 2022

Here are the simplified steps to create a Next.js React app and add TypeScript to the mix. This tutorial combines my Create a Next.js app and Add TypeScript to Next.js posts.

Create a Next.js App

Let's use npx and create-next-app.

npx \
create-next-app nextjs-app \
--use-npm \
--example \
"https://github.com/vercel/next-learn/tree/master/basics/learn-starter"

Add TypeScript

# Enter your app's directory
cd nextjs-app
# Create an empty TypeScript configuration file
touch tsconfig.json
# Install TypeScript, React Types, and Node Types
npm install --save-dev typescript @types/react @types/node

You can customize your TypeScript in tsconfig.json.

Run the app in development mode

npm run dev
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000

You should be able to access the site at http://localhost:3000.

Build & Run for Production

npm run build
npm start
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000

From index.js into index.tsx

Your application is now ready to be written in TypeScript. The example we've used only has one file named index.js. Rename it to index.tsx and re-write the JavaScript code (and any new code you add to the app) in TypeScript.

Hands-on tutorial

You can watch my step-by-step video on How to build a Next.js app with React & TypeScript.

JUNE 12, 2022

Here's how to find an item with a matching property value. We're querying an array of items in search of an entry, in this case, looking for a person by name and then retrieving their age.

// Define the Person type
type Person = {
    name: string;
    age: number;
}

// Define an array of persons
const people: Person[] = [
    {
      name: 'James',
      age: 24,
    },
    {
      name: 'Claire',
      age: 13,
    },
    {
      name: 'John',
      age: 42,
    }
  ];
  
  const person = people.find(p => p.name == 'John') as Person;
  // {
  //   name: 'John',
  //   age: 42,
  // }
  
  console.log(`${person.name} is ${person.age}.`);
  // John is 42.

Before you go

If you found this useful, you might want to join my newsletter; or take a look at other posts on TypeScript.

JUNE 11, 2022

Here are the steps to add TypeScript to your Next.js React application.

I assume you have a Next.js React application that can run in development mode. If that's not the case, Create a Next.js app first.

# Enter the directory of your app
cd nextjs-app
# Run Next.js in development
npm run dev
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000

If you can access your site at http://localhost:3000, you're good to go.

Create a tsconfig.json file

# Create an empty TypeScript configuration file
touch tsconfig.json

Simply by creating a tsconfig.json file and restarting the application, Next.js will warn us that we're trying to work with TypeScript and have to install a set of required dependencies.

# Stop the running app with `CMD + C` (or `CTRL + C` on Windows)
# Run Next.js in development once again
npm run dev

You should receive the following warning when restarting the app.

ready - started server on 0.0.0.0:3000, url: http://localhost:3000
It looks like you're trying to use TypeScript but do not have
the required package(s) installed.

Please install typescript, @types/react, and @types/node by running:

  npm install --save-dev typescript @types/react @types/node

If you are not trying to use TypeScript, please remove the
tsconfig.json file from your package root (and any TypeScript
files in your pages directory).

Install TypeScript, React Types, and Node Types

npm install --save-dev typescript @types/react @types/node

Run your app

npm run dev
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000
# We detected TypeScript in your project and created a tsconfig.json
# file for you.

Note that Next.js detected the tsconfig.json file, verified our dependencies were installed, and then populated our empty TypeScript configuration file with a boilerplate JSON object.

// tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "incremental": true,
    "esModuleInterop": true,
    "module": "esnext",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

From index.js into index.tsx

Your application is now ready to be written in TypeScript. The example we've used only has one file named index.js. Rename it to index.tsx and re-write the JavaScript code (and any new code you add to the app) in TypeScript.

Learning More

If you want to learn more, you can watch my video on How to build a Next.js app with React & TypeScript and take a look at Next.js's official TypeScript tutorial.

JUNE 4, 2022

As the official Create a Next.js App tutorial says, "there are many important details you need to consider to build a complete web application with React from scratch," but here I'm trying to get started as fast as possible.

Create a Next.js App

Let's use npx and create-next-app.

npx \
create-next-app nextjs-app \
--use-npm \
--example \
"https://github.com/vercel/next-learn/tree/master/basics/learn-starter"

Your fresh Next.js app is now in the nextjs-app directory.

Run the App in Development

Now enter the directory and run the app in development mode.

cd nextjs-app
npm run dev
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000

You should be able to access the site at http://localhost:3000.

Build & Run for Production

npm run build
npm start
ready - started server on 0.0.0.0:3000, url: http://localhost:3000

Add TypeScript to Next.js

If you want to use TypeScript instead of JavaScript on your Next.js React app, read how to Add TypeScript to Next.js. I also have a step-by-step video on How to build a Next.js app with React & TypeScript.

MAY 27, 2022

I'm writing a series of posts on how to create a Next.js React app with and without TypeScript, trying to summarize the required steps.

# Create a Next.js React JavaScript app with npx
npx \
create-next-app nextjs-app \
--use-npm \
--example \
"https://github.com/nonoesp/next-learn/tree/master/basics/learn-starter"
# Enter the app's directory
cd nextjs-app
# Start the app in development mode
npm run dev
# > dev
# > next dev
#
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000
# wait  - compiling...
# event - compiled client and server successfully in 944 ms (113 modules)

You should be able to access the site at http://localhost:3000. =)

DECEMBER 21, 2021

Say you have a long list of numbers and you want to add them together, or maybe you wish to multiply them or do some other series of operations, to all of them. You can use a reducer, and here's a sample of how to define a reducer as a simply add-two function to add an entire list of numbers.

const numbers = [20, 30, 50];
const reducer = (previousValue, currentValue) => {
  return previousValue + currentValue;
}
const result = numbers.reduce(reducer); // 100

You could easily parse a plain-text list as well.

const text = '1.75 Milk\n0.70 Bread\n2.56 Yogurt';
const numbers = text.split('\n').map(s => parseFloat(s.split(' ')[0]));
const reducer = (previousValue, currentValue) => {
  return previousValue + currentValue;
}
const result = numbers.reduce(reducer); // 5.01

SEPTEMBER 27, 2021

From MongoDB's JSON Schema Examples Tutorial page:

JSON Schema is an IETF standard providing a format for what JSON data is required for a given application and how to interact with it. Applying such standards for a JSON document lets you enforce consistency and data validity across similar JSON data.

The purpose of a JSON Schema is to define the allowed property names and data types allowed to facilitate the validation of a given JSON object. This reminds me of TypeScript definitions, where type-checking happens by default after you've instantiated a given interface or class.

LAST UPDATED JULY 26, 2022

You can measure the time elapsed during the execution of TypeScript commands by keeping a reference to the start time and then subtracting the current time at any point on your program from that start time to obtain the duration between two points in time.

const start = new Date().getTime();

// Run some code..

let elapsed = new Date().getTime() - start;

Let's create two helper functions to get the current time (i.e. now) and the elapsed time at any moment.

// Returns current time
// (and, if provided, prints the event's name)
const now = (eventName = '') => {
    if (eventName) {
      console.log(`Started ${eventName}..`);
    }
    return new Date().getTime();
}

// Store current time as `start`
let start = now();

// Returns time elapsed since `beginning`
// (and, optionally, prints the duration in seconds)
const elapsed = (beginning = start, log = false) => {
    const duration = new Date().getTime() - beginning;
    if (log) {
        console.log(`${duration/1000}s`);
    }
    return duration;
}

With those utility functions defined, we can measure the duration of different events.

// A promise that takes X ms to resolve
function sleep(ms: any) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// Measure duration (while waiting for 2 seconds)
(async function demo() {
    const waitInSeconds = 2;
    let beginning = now(`${waitInSeconds}-second wait`);
    // Prints Started 2-second wait..
    await sleep(waitInSeconds * 1000);
    elapsed(beginning, true);
    // Prints 2.004s
})();

To avoid warnings, you must set target to es2015 in your tsconfig.json.


Continue reading ›

FEBRUARY 6, 2020

npx and create-react-app make it easy to create a new app running React and TypeScript.

npx create-react-app my-app --template typescript

Then you go into the folder and run the app.

cd my-app
npm start

You can create a JavaScript (non-TypeScript) app by removing the last bit—--template typescript. And you can also run the app with yarn start.

If, as I was, you're not getting the app working, you might have an older global installation of create-react-app. In my case I installed it with npm install -g create-react-app (which I could verify by running create-react-app -V on the Terminal. To make sure npx uses the latest version of create-react-app you need to uninstall the global version installed with npm.

npm uninstall -g create-react-app

Continue reading ›

JULY 24, 2019

This example uses regular expressions (RegExp) to replace multiple appearances of a substring in a string.

const string = `The car is red. The car is black.`;

const replacedString = string.replace(/car|is/g, "·····");

console.log(replacedString);
// returns The ····· ····· red. The ····· ····· black.

Continue reading ›

JULY 24, 2019

Here is an example of nested Promise.all() calls. We are using the Fetch API to load a given path or URL, then requesting the arrayBuffer() of each of the responses we get back. This is a trivial problem if we do it all asynchronously, but we want to do something with the output buffers when we have them all available, and not one by one.

Specifically, this code tries to (1) fetch an array of images; (2) get their array buffers; (3) then obtain their base64 representation. In essence, map an array of images (by providing their paths or URLs) to their corresponding base64 string.


While this technique works in both TypeScript and JavaScript, the code is only shown in TypeScript.

Approach 1: Verbose

const images = [/* Array of image URLs (or local path if running in Electron) */]

Promise.all(images.map((url) => fetch(url))).then((responses: any) => {

    return Promise.all(responses.map((res: Response) => res.arrayBuffer())).then((buffers) => {
        return buffers;
    });

}).then((buffers: any) => {

    return Promise.all(buffers.map((buffer: ArrayBuffer) => {
        return this.arrayBufferToBase64(buffer);
    }));

}).then((imagesAsBase64: any) => {

    // Do something with the base64 strings
    window.console.log(imagesAsBase64);

});

Approach 2: Simplified

const layerImages = [/* Array of image URLs (or local path if running in Electron) */]

Promise.all(layerImages.map((url) => fetch(url))).then((responses: any) => {

    return Promise.all(responses.map((res: Response) => res.arrayBuffer())).then((buffers) => {
        return buffers.map((buffer) => this.arrayBufferToBase64(buffer));
    });

}).then((imagesAsBase64: any) => {

    // Do something with the base64 strings
    window.console.log(imagesAsBase64);

});

Array Buffer to base64

// source: stackoverflow.com
private arrayBufferToBase64(buffer: any) {
    let binary = "";
    const bytes = [].slice.call(new Uint8Array(buffer));
    bytes.forEach((b: any) => binary += String.fromCharCode(b));
    // Inside of a web tab
    return window.btoa(binary);
}

Before you go

If you found this useful, you might want to join my newsletter; or take a look at other posts about code, TypeScript, and React.

MAY 15, 2019

A while ago we had the need to grab the App window variable (exposed by CefSharp) and we were extending the Window interface to do that. There seems to be a better way to get variables that are define in the Window environment.

I learned this from this link An advanced guide on how to setup a React and PHP.

If you are defining a variable or object you want to read from React (like in CefSharp, o directly in the HTML like in the screenshot)

// inside of your app entry HTML file's header
<script>
var myApp = {
  user: "Name",
  logged: true
}
</script>

You can do a declare module 'myApp' in index.d.ts, then add the myApp variable as a external library in Webpack's config file

externals: {
  myApp: `myApp`,
},

Then you can import as if it was a module in TypeScript (or JavaScript files) with React

import myApp from 'myApp';

And you can even use TypeScript destructuring technique to get internal properties directly

const { user: { name, email}, logged } = myApp;

Before you go

If you found this useful, you might want to join my newsletter; or take a look at other posts about code, TypeScript, and React.

FEBRUARY 25, 2019

In trying to export my React's Redux store from index.tsx to be used somewhere else outside of the React application, I was getting an Invariant Violation: Target container is not a DOM element error while running Jest tests (with Enzyme and Webpack) in the App component (App.tsx).

I found a solution to this error for my use case, which was using the same Redux store React is using outside of React.

The error

The initial code that didn't work when testing React looked like this.

// index.tsx

import * as React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import { applyMiddleware, compose, createStore } from "redux";
import App from "./components/App";
import { rootReducer } from "./store/reducers";
import { initialState } from "./store/state";

const middlewares = [];

export const store = createStore(
    rootReducer,
    initialState,
    compose(applyMiddleware(...middlewares)),
);

render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById("root"),
);

The solution

Separate the Redux store logic into a new file named store.ts, then create a default export (to be used by index.tsx, i.e., the React application) and a non-default export with export const store (to be used from non-React classes), as follows.

// store.ts

import { applyMiddleware, compose, createStore } from "redux";
import logger from "redux-logger";
import { rootReducer } from "./store/reducers";
import { initialState } from "./store/state";

const middlewares = [];

export const store = createStore(
    rootReducer,
    initialState,
    compose(applyMiddleware(...middlewares)),
);

export default store;
// updated index.tsx

import * as React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux";
import App from "./components/App";
import store from "./store";

render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById("root"),
);

Using the Redux store in non-React classes

// MyClass.ts

import { store } from "./store"; // store.ts

export default class MyClass {
  handleClick() {
    store.dispatch({ ...new SomeAction() });
  }
}

The default export

A small note before you go. Here is how to use the default and the non-default exports.

  • default export store; is used with import store from "./store";
  • export const store = ... is used with import { store } from "./store";

Before you go

If you found this useful, you might want to join my newsletter; or take a look at other posts about code, TypeScript, and React.

NOVEMBER 14, 2018

for...of1

const numbers = [1, 3, 100, 24];
for (const item of numbers) {
  console.log(item); // 1, 3, 100, 24
}

Before you go

If you found this useful, you might want to join my newsletter; or take a look at other posts about code, TypeScript, and React.

AUGUST 28, 2018

In TypeScript, as in other languages, Array.map allows you to apply a function to each of the items on a list or array. You can either pass an existing function which will take each of the items as its input parameter (say, the existing Math.sqrt function, or one that you define).

let list = [0, 1, 2, 3]; // [0, 1, 2, 3]
list.map(Math.sqrt); // [ 0, 1, 1.414.., 1.732.. ]

Or you can also define a lambda function on-the-go.

let list = [0, 1, 2, 3]; // [0, 1, 2, 3]
list.map((value, key, all) => {
  list[key] = value * 2;
}); // [ 0, 2, 4, 6]

Before you go

If you found this useful, you might want to join my newsletter; or take a look at other posts about code, TypeScript, and React.

Want to see older publications? Visit the archive.

Listen to Getting Simple .