Skip to content

Instantly share code, notes, and snippets.

@superjojo140
Last active August 14, 2025 09:12
Show Gist options
  • Save superjojo140/1c141912d3ae9b2ae5e8d052e30b0e53 to your computer and use it in GitHub Desktop.
Save superjojo140/1c141912d3ae9b2ae5e8d052e30b0e53 to your computer and use it in GitHub Desktop.
Typescript - NPM - Node - ESM Cheatsheet

Typescript

tsconfig

{
  "compilerOptions": {
    "target": "esnext", //Output JS Version (newer version -> less polyfills but also less browser compatibility)
    "module": "esnext", //see note below
    "declaration": true, //Generate .d.ts files
    "outDir": "dist",
    "strict": true,
    "esModuleInterop": true, //Clean import of "old" CommonJS Modules (the require() syntax)
    "moduleResolution": "node", //see note below
    "skipLibCheck": true,
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}

Note on the module option

Node.js (CJS): "CommonJS" + "type": "commonjs" in package.json → Uses require, works in most current Node apps.

Node.js (ESM): "ESNext" or "NodeNext" + "type": "module" in package.json → Uses import, future-proof, but requires .js in import paths.

Bundlers (Vite, Webpack, Rollup): "ESNext" is best – clean output for tree shaking.

Browser without bundler: "System" or "UMD" if loading with <script type="module">.

moduleResolution option

  • "bundler" ✅ Best for ESM libraries and bundler-based builds. Assumes extension remapping (like .ts → .js) happens in bundler.
  • "node" Good for Node.js/CommonJS projects. Follows Node's module resolution rules. Requires you to manually fix import paths/extensions in ESM.
  • "node16" / "nodenext" Only needed if you're using "module": "NodeNext" and targeting pure native Node.js resolution without a bundler.
  • "classic" Old default for pre-ESM days. Almost never used anymore.

Record Utility Type

The Record<K, T> utility type in TypeScript constructs an object type whose property keys are K and property values are T.

// Creates an object with string keys and number values
const scores: Record<string, number> = {
  alice: 10,
  bob: 15,
};

Omit Utility Type

To describe a datatype minus a specific property in TypeScript, use the Omit<T, K> utility type. It creates a new type by removing property K from type T.

type User = {
  id: number;
  name: string;
  email: string;
};

// Remove the 'email' property
type UserWithoutEmail = Omit<User, 'email'>;

Array destruction

In TypeScript (and JavaScript), array destructuring is a syntax that lets you unpack values from arrays into separate variables in a concise way.

Example:

const arr = [1, 2, 3];
//The variables on the left ([a, b, c]) match the order of elements in the array.
const [a, b, c] = arr; // a=1, b=2, c=3

// Skip elements
const [, second] = arr; // second=2

tsconfig for backend

Writing your backend in typescript, needs an compilation step to js to execute with nodeJs. This can be done with tsc && node (better for productive) or ts-node (easier for development) directly.

Your backend code needs its own tsconfig file. Using modern ESM imports can be tricky (as always...). But this config seems to work for me:

{
    "compilerOptions": {
        "module": "nodenext",
        "sourceMap": true,
        "target": "esnext",
        "allowJs": true,
        "esModuleInterop": true,
        "moduleResolution": "nodenext"
    },
    "include": [
        "./**/*.ts"
    ],
}

Typescript an mysql queries

mysql2 package

Use the mysql2 npm package with promises (mysql package is deprecated)

import mysql from "mysql2/promise";

const userId = 1;
const conn = await mysql.createConnection({ host: "localhost", user: "root", database: "test" });

//conn.execute() returns an array with two items. The interesting one is the first item that is selected with array destructing [rows] = ...
const [rows] = await conn.execute("SELECT * FROM users WHERE id = ?", [userId]);
console.log(rows);

return types

Typescript cannot know whats the datatype of the query's result. For example that can be a set of data from your DB (eg. for a SELECT statement) or some operational feedback (eg. for an INSERT statement). You can use a type parameter in typescript to define whats the query's return type:

const queryCmd = `SELECT * FROM projects WHERE id = ?`;
const [rows] = await conn.execute<RowDataPacket[]>(queryCmd, [projectId]);
return rows[0]; //Returns data of the first result row

const queryCmd = `INSERT INTO projects (title, description, notes) VALUES (?, ?, ?)`;
const [result] = await conn.execute<ResultSetHeader>(queryCmd, [title, description, notes]);
return result.insertId; //Returns the id of the inserted element

Express.js in Typescript

Response Statuscode

  • 200 OK + JSON → Common when you want to return the updated resource
  • 204 No Content → Common when you just want to confirm success without sending data
  • 404 Not Found → If the resource ID doesn’t exist
  • 400 Bad Request → If the input is invalid

NPM

Linking a local developed npm package

Option1 npm link (good for development/testing)

This sets up a symlink between your local package and your consuming project. 🔄 Changes in my-lib will be reflected in main-app without reinstalling.

Steps:

#Go to the package folder:
cd path/to/my-lib
npm link

#In the project that uses the lib:
cd path/to/main-app
npm link my-lib
# -> Now your app uses a symlink to your local my-lib.

#To undo:
npm unlink my-lib

Export stuff from npm package to use in your project

To export multiple static utility classes from your TypeScript-based npm library, you should create a public API entry point (usually src/index.ts) that re-exports your classes clearly.

Example Structure

my-lib/
├── src/
│   ├── string-utils.ts
│   ├── date-utils.ts
│   └── index.ts         ← Public API
├── package.json
└── tsconfig.json

index.ts – the public API

This file re-exports your classes:

export { StringUtils } from './string-utils';
export { DateUtils } from './date-utils';

//or this way
export * from './string-utils';
export * from './date-utils';

//Or if you want to group them:
import { StringUtils } from './string-utils';
import { DateUtils } from './date-utils';

export {
  StringUtils,
  DateUtils
};

Consumers Can Use It Like This

After installing your package (npm install my-lib), users can do:

import { StringUtils, DateUtils } from 'my-lib';

console.log(StringUtils.capitalize('hello'));
console.log(DateUtils.formatISO(new Date()));

package.json Setup

Make sure your package.json points to the correct compiled entry:

{
  "name": "my-lib",
  "type": "module",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "types": "./dist/index.d.ts"
    }
  }
}

Sweetalert

There are the sweetalert and the sweetalert2 packages on npm.

The old sweetalert package is not really maintained since years. There is an 1.x and 2.x version of the sweetalert package. Using this versions is quite different at some points (callback vs promises, CSS injection etc.)

Im using the old old 1.1.3 version of sweetalert in swu-core. Since it works best for my codebase.

I dont want to use the modern and actively maintained sweetalert2 package because this contains protestware code according the war in Ukraine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment