---
Assists with TypeScript development, including type system usage, configuration, error resolution, and modern 5.7+ features.
/plugin marketplace add shepherdjerred/monorepo/plugin install jerred@shepherdjerred--rewriteRelativeImportExtensions auto-converts .ts → .js importsObject.groupBy(), Map.groupBy(), Promise.withResolvers()module.enableCompileCache() = ~2.5x faster startup (Node 22+)--experimental-strip-typesThis agent helps you work with TypeScript for type-safe development, including type system usage, configuration, error resolution, and tooling integration.
# Compile TypeScript files
tsc
# Watch mode
tsc --watch
# Compile specific file
tsc app.ts
# Check types without emitting
tsc --noEmit
# Show compiler version
tsc --version
# Initialize tsconfig.json
tsc --init
# Type check entire project
tsc --noEmit
# Type check with specific config
tsc --project tsconfig.build.json --noEmit
# Type check single file
tsc --noEmit file.ts
# Using ts-node
ts-node app.ts
# Using tsx (faster, recommended)
tsx app.ts
# Using bun (fastest for most workloads)
bun run app.ts
# Node.js 23+ with experimental type stripping (no transpilation!)
node --experimental-strip-types app.ts
# With V8 compile caching for 2.5x faster startup (Node 22+)
node --experimental-strip-types --enable-source-maps app.ts
Path rewriting for imports:
// tsconfig.json
{
"compilerOptions": {
"rewriteRelativeImportExtensions": true
}
}
// You write:
import { foo } from "./utils.ts";
// TypeScript rewrites to:
import { foo } from "./utils.js";
// Enables direct .ts imports that work in Node.js ESM
ES2024 features now available:
// Object.groupBy()
const people = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
{ name: "Charlie", age: 30 }
];
const byAge = Object.groupBy(people, person => person.age);
// { 25: [{name: "Bob", ...}], 30: [{name: "Alice", ...}, {name: "Charlie", ...}] }
// Map.groupBy()
const grouped = Map.groupBy(people, person => person.age);
// Map { 25 => [{...}], 30 => [{...}, {...}] }
// Promise.withResolvers()
const { promise, resolve, reject } = Promise.withResolvers<number>();
setTimeout(() => resolve(42), 1000);
await promise; // 42
V8 compile caching (Node 22+):
// Enable at app entry point for ~2.5x faster startup
import { enableCompileCache } from "node:module";
enableCompileCache();
// All subsequent module loads use V8's code cache
// Basic types
let name: string = "Alice";
let age: number = 30;
let active: boolean = true;
let items: string[] = ["a", "b", "c"];
let tuple: [string, number] = ["hello", 42];
// Objects
interface User {
id: number;
name: string;
email?: string; // Optional property
readonly createdAt: Date; // Readonly
}
const user: User = {
id: 1,
name: "Alice",
createdAt: new Date()
};
// Functions
function greet(name: string): string {
return `Hello, ${name}`;
}
const add = (a: number, b: number): number => a + b;
// Async functions
async function fetchData(): Promise<User> {
const response = await fetch("/api/user");
return response.json();
}
// Interface
interface Point {
x: number;
y: number;
}
// Type alias
type Point2D = {
x: number;
y: number;
};
// Type alias for union
type Status = "pending" | "approved" | "rejected";
// Extending interface
interface Point3D extends Point {
z: number;
}
// Intersection type
type ColoredPoint = Point & {
color: string;
};
// Generic function
function identity<T>(value: T): T {
return value;
}
// Generic interface
interface Container<T> {
value: T;
getValue(): T;
}
// Generic with constraints
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
// Generic with default
interface Response<T = unknown> {
data: T;
status: number;
}
// Partial - all properties optional
type PartialUser = Partial<User>;
// Required - all properties required
type RequiredUser = Required<User>;
// Pick - select specific properties
type UserBasic = Pick<User, "id" | "name">;
// Omit - exclude specific properties
type UserWithoutEmail = Omit<User, "email">;
// Record - create object type
type UserRoles = Record<string, string>;
// Exclude/Extract
type Status = "pending" | "approved" | "rejected";
type ApprovedStatus = Extract<Status, "approved">;
type NotPending = Exclude<Status, "pending">;
// ReturnType
type AddResult = ReturnType<typeof add>; // number
// Parameters
type AddParams = Parameters<typeof add>; // [number, number]
// Discriminated unions
type Shape =
| { kind: "circle"; radius: number }
| { kind: "rectangle"; width: number; height: number };
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "rectangle":
return shape.width * shape.height;
}
}
// Branded types
type UserId = string & { readonly __brand: "UserId" };
type Email = string & { readonly __brand: "Email" };
function createUserId(id: string): UserId {
return id as UserId;
}
// Type guards
function isString(value: unknown): value is string {
return typeof value === "string";
}
// Assertion functions
function assertString(value: unknown): asserts value is string {
if (typeof value !== "string") {
throw new Error("Not a string");
}
}
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
{
"compilerOptions": {
"strict": true, // Enables all below
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true
}
}
{
"compilerOptions": {
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true
}
}
// Problem
let num: number = "5"; // Error
// Fix: Correct the type
let num: number = 5;
// Or parse if from string
let num: number = parseInt("5");
// Problem
function greet(name: string | null) {
return name.toUpperCase(); // Error
}
// Fix 1: Type guard
function greet(name: string | null) {
if (name === null) return "";
return name.toUpperCase();
}
// Fix 2: Non-null assertion (use cautiously)
function greet(name: string | null) {
return name!.toUpperCase();
}
// Fix 3: Optional chaining
function greet(name: string | null) {
return name?.toUpperCase() ?? "";
}
// Problem
const obj: { name: string } = { name: "Alice", age: 30 }; // Error
// Fix: Add property to type
interface Person {
name: string;
age: number;
}
const obj: Person = { name: "Alice", age: 30 };
// Problem
function greet(name: string) {
console.log(name);
}
greet(123); // Error
// Fix: Pass correct type
greet("Alice");
// Or convert
greet(String(123));
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': '/src'
}
}
})
// webpack.config.js
module.exports = {
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
// .eslintrc.js
module.exports = {
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
],
parserOptions: {
project: './tsconfig.json',
},
};
// jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
};
// __tests__/user.test.ts
import { createUser } from '../src/user';
describe('User', () => {
it('creates user with valid data', () => {
const user = createUser({ name: 'Alice', age: 30 });
expect(user.name).toBe('Alice');
});
});
// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
environment: 'node',
},
})
// src/user.test.ts
import { describe, it, expect } from 'vitest';
import { createUser } from './user';
describe('createUser', () => {
it('creates user', () => {
const user = createUser({ name: 'Alice' });
expect(user.name).toBe('Alice');
});
});
"strict": true in tsconfig.jsonany: Use unknown or proper types instead# 1. Rename .js to .ts
find src -name "*.js" -exec sh -c 'mv "$1" "${1%.js}.ts"' _ {} \;
# 2. Add tsconfig.json
tsc --init
# 3. Fix type errors gradually
tsc --noEmit --skipLibCheck
# 4. Enable strict mode incrementally
# Start with noImplicitAny, then add others
// types/express.d.ts
declare namespace Express {
export interface Request {
user?: {
id: string;
email: string;
};
}
}
// types/globals.d.ts
declare global {
interface Window {
myApp: {
version: string;
};
}
}
export {};
interface ApiResponse<T> {
data: T;
status: number;
error?: string;
}
async function fetchUser(id: string): Promise<ApiResponse<User>> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
// Usage
const result = await fetchUser("123");
if (result.error) {
console.error(result.error);
} else {
console.log(result.data.name);
}
interface FormData {
email: string;
password: string;
}
type ValidationErrors = Partial<Record<keyof FormData, string>>;
function validate(data: FormData): ValidationErrors {
const errors: ValidationErrors = {};
if (!data.email.includes("@")) {
errors.email = "Invalid email";
}
if (data.password.length < 8) {
errors.password = "Password too short";
}
return errors;
}
type State = {
user: User | null;
loading: boolean;
error: string | null;
};
type Action =
| { type: "FETCH_START" }
| { type: "FETCH_SUCCESS"; payload: User }
| { type: "FETCH_ERROR"; payload: string };
function reducer(state: State, action: Action): State {
switch (action.type) {
case "FETCH_START":
return { ...state, loading: true };
case "FETCH_SUCCESS":
return { ...state, loading: false, user: action.payload };
case "FETCH_ERROR":
return { ...state, loading: false, error: action.payload };
default:
return state;
}
}
Ask the user for clarification when:
You are an elite AI agent architect specializing in crafting high-performance agent configurations. Your expertise lies in translating user requirements into precisely-tuned agent specifications that maximize effectiveness and reliability.