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(`, `)
}
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
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.
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!)
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}</>
}
Here's how to define simple async
functions in TypeScript.
(async (/*arguments*/) => {/*function logic*/})(/*values*/);
// Define an asynchronous function.
const helloAsync = async() => { console.log("Hey, Async!"); }
// Call it asynchronously.
helloAsync();
(async(text: string) => { console.log(text); })("Hello, Async!")
(async(text: string) => { setTimeout(() => console.log(text), 2000); })("Hello, Async!")
// 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!`);
})();
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
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
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.
How to build a client for real-time communication with WebSockets in TypeScript using the ws
NPM package.
How to build a server for real-time communication with WebSockets in TypeScript using the ws
NPM package.
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.
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"
# 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.
npm run build
npm start
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000
You can watch my step-by-step video on How to build a Next.js app with React & TypeScript.
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.
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"
# 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
.
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.
npm run build
npm start
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000
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.
You can watch my step-by-step video on How to build a Next.js app with React & TypeScript.
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.
If you found this useful, you might want to join my newsletter; or take a look at other posts on TypeScript.
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.
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).
npm install --save-dev typescript @types/react @types/node
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"
]
}
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.
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.
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.
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.
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.
npm run build
npm start
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
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.
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. =)
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
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.
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
.
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
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.
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.
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);
});
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);
});
// 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);
}
If you found this useful, you might want to join my newsletter; or take a look at other posts about code, TypeScript, and React.
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;
If you found this useful, you might want to join my newsletter; or take a look at other posts about code, TypeScript, and React.
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 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"),
);
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"),
);
// MyClass.ts
import { store } from "./store"; // store.ts
export default class MyClass {
handleClick() {
store.dispatch({ ...new SomeAction() });
}
}
default
exportA 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";
If you found this useful, you might want to join my newsletter; or take a look at other posts about code, TypeScript, and React.
const numbers = [1, 3, 100, 24];
for (const item of numbers) {
console.log(item); // 1, 3, 100, 24
}
If you found this useful, you might want to join my newsletter; or take a look at other posts about code, TypeScript, and React.
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]
If you found this useful, you might want to join my newsletter; or take a look at other posts about code, TypeScript, and React.