Skip to content

Instantly share code, notes, and snippets.

@superjojo140
Last active August 12, 2025 09:18
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

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

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"
    }
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment