AgentStack
SKILL unreviewed MIT Self-run

Javascript Typescript

skill-kinhluan-skills-javascript-typescript · by kinhluan

Modern JavaScript and TypeScript development best practices (2024-2025). Use for frontend, backend, full-stack, React/Next.js, Node.js, testing, linting, and production deployment.

No reviews yet
0 installs
9 views
0.0% view→install

Install

$ agentstack add skill-kinhluan-skills-javascript-typescript

Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.

Security review

⚠ Flagged

1 finding(s); flagged for manual review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures
  • high Pipes remote content directly into a shell (remote code execution).

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Javascript Typescript? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

JavaScript & TypeScript

Modern JS/TS development covering project setup, TypeScript strict mode, React/Next.js patterns, state management, testing, linting, and production deployment. Targets Node.js 20+, TypeScript 5.5+, React 19+, pnpm, bun.

> "Make invalid states unrepresentable." — The TypeScript Way


1. Project Setup

Package Manager

| Tool | Best For | Install | Speed | Lockfile | |---|---|---|---|---| | pnpm (recommended) | Monorepos, disk efficiency, strict dependency resolution | corepack enable && corepack prepare pnpm@latest --activate | Fast | pnpm-lock.yaml | | bun | Runtime + bundler + test runner in one, fastest install | curl -fsSL https://bun.sh/install \| bash | Fastest | bun.lockb | | npm | Default, no setup needed | Built-in with Node.js | Slowest | package-lock.json |

pnpm workflow:

# Enable corepack (Node.js 16.13+) — one-time setup
corepack enable
corepack prepare pnpm@latest --activate

# Project init
pnpm init
pnpm add typescript react react-dom
pnpm add -D @types/react @types/react-dom eslint prettier vitest

# Monorepo workspace
pnpm-workspace.yaml:
  packages:
    - 'packages/*'
    - 'apps/*'

# Workspace commands
pnpm -r install          # install all workspaces
pnpm --filter web build  # build only 'web' package
pnpm -r exec tsc --noEmit # type-check all

bun workflow:

# Install (macOS/Linux)
curl -fsSL https://bun.sh/install | bash

# Project init — creates bun.lockb, package.json, tsconfig.json
bun init

# Install dependencies (10-100x faster than npm)
bun add typescript react react-dom
bun add -D @types/react @types/react-dom

# Run scripts (no need for 'run')
bun dev                  # runs 'dev' script
bun test                 # built-in test runner (Jest-compatible)
bun build                # built-in bundler

# Runtime: drop-in Node.js replacement
bun run server.ts        # instead of node server.ts
bun --hot server.ts      # hot reload (no nodemon needed)

When to choose what:

Monorepo with 5+ packages     → pnpm (workspace filtering, strict hoisting)
Single app, speed critical    → bun (runtime + bundler + test in one)
Enterprise / CI consistency   → pnpm (mature, predictable, corepack)
Quick prototype / side project → bun (fastest everything)

Lockfile hygiene (critical for CI reproducibility):

# pnpm — deterministic, content-addressable
pnpm install --frozen-lockfile   # CI: fail if lockfile out of sync
pnpm install --no-frozen-lockfile # Local: update lockfile

# bun — binary lockfile, very fast
bun install --frozen-lockfile     # CI
bun install --no-save             # Local, don't update lockfile

TypeScript Configuration (tsconfig.json)

{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@/components/*": ["./src/components/*"],
      "@/lib/*": ["./src/lib/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Key strict flags: | Flag | Effect | |---|---| | strictNullChecks | null/undefined are separate types | | noUncheckedIndexedAccess | arr[0] is T \| undefined | | exactOptionalPropertyTypes | ? means absent, not \| undefined |


2. Type Best Practices

Prefer Interfaces for Object Shapes

// ✅ Interface — extensible, better error messages
interface User {
  id: string;
  name: string;
  email: string;
}

// ✅ Type — for unions, tuples, mapped types
type Status = 'idle' | 'loading' | 'success' | 'error';
type ApiResponse = { data: T; status: number } | { error: string; status: number };

// ❌ Don't use type for simple objects (unless you need union)

Discriminated Unions

type LoadingState = { status: 'loading' };
type SuccessState = { status: 'success'; data: T };
type ErrorState = { status: 'error'; error: string };

type AsyncState = LoadingState | SuccessState | ErrorState;

function handleState(state: AsyncState): T | null {
  switch (state.status) {
    case 'loading': return null;
    case 'success': return state.data;  // TypeScript knows data exists
    case 'error': throw new Error(state.error);
    default: return exhaustiveCheck(state);
  }
}

function exhaustiveCheck(x: never): never {
  throw new Error(`Unhandled case: ${x}`);
}

Branded Types for Type-Safe IDs

type UserId = string & { __brand: 'UserId' };
type OrderId = string & { __brand: 'OrderId' };

function createUserId(id: string): UserId {
  return id as UserId;
}

// Now this is a type error:
// const userId: UserId = createUserId('123');
// const orderId: OrderId = userId;  // ❌ Compile error

Utility Types

// Partial, Required, Pick, Omit
 type UpdateUserInput = Partial>;

// ReturnType, Parameters
 type ApiReturn = ReturnType;
 type ApiParams = Parameters;

// Record, Readonly
 type ConfigMap = Record;
 type ImmutableUser = Readonly;

// Awaited (unwraps Promise)
 type UserData = Awaited>;

3. Modern JavaScript (ES2022+)

Nullish Coalescing & Optional Chaining

const value = config.timeout ?? 5000;  // only null/undefined, not 0 or ''
const name = user?.profile?.name ?? 'Anonymous';

Top-Level Await

// In ES modules
const data = await fetch('/api/config').then(r => r.json());
export const config = data;

Private Class Fields

class Counter {
  #count = 0;  // truly private, not just convention

  increment() {
    this.#count++;
    return this.#count;
  }

  get #formatted() {  // private getter
    return `Count: ${this.#count}`;
  }
}

Array Methods

const nums = [1, 2, 3, 4, 5];

// Modern methods (no mutation)
const doubled = nums.map(n => n * 2);
const evens = nums.filter(n => n % 2 === 0);
const sum = nums.reduce((a, b) => a + b, 0);
const firstEven = nums.find(n => n % 2 === 0);  // number | undefined
const hasEven = nums.some(n => n % 2 === 0);
const allPositive = nums.every(n => n > 0);

// toSorted, toReversed, toSpliced (ES2023 — non-mutating)
const sorted = nums.toSorted((a, b) => b - a);
const reversed = nums.toReversed();

4. React 19+ Patterns

Server Components (Next.js App Router)

// app/page.tsx — Server Component by default
import { db } from '@/lib/db';

export default async function Page() {
  const users = await db.query('SELECT * FROM users');  // runs on server

  return (
    
      Users
      
        {/* Client Component */}
    
  );
}

// components/UserForm.tsx — Client Component
'use client';

import { useState } from 'react';

export function UserForm() {
  const [name, setName] = useState('');
  // ... client-side interactivity
}

Hooks Best Practices

import { useState, useEffect, useCallback, useMemo, useRef } from 'react';

// Custom hook for data fetching
function useApi(url: string) {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const controller = new AbortController();
    fetch(url, { signal: controller.signal })
      .then(r => r.json())
      .then(setData)
      .catch(setError)
      .finally(() => setLoading(false));
    return () => controller.abort();
  }, [url]);

  return { data, error, loading };
}

// Usage
function UserProfile({ userId }: { userId: string }) {
  const { data: user, error, loading } = useApi(`/api/users/${userId}`);

  if (loading) return ;
  if (error) return ;
  if (!user) return ;

  return ;
}

useMemo / useCallback

// ✅ Use when computation is expensive
const sortedUsers = useMemo(
  () => users.sort((a, b) => a.name.localeCompare(b.name)),
  [users]
);

// ✅ Use when passing callbacks to optimized children
const handleSubmit = useCallback(
  (data: FormData) => {
    api.submit(data);
  },
  []
);

// ❌ Don't overuse — React is fast enough for simple cases

React 19 Actions

// Server Actions (Next.js)
'use server';

export async function createUser(formData: FormData) {
  'use server';
  const name = formData.get('name') as string;
  await db.insert('users', { name });
  revalidatePath('/users');
}

// Client usage with useActionState
import { useActionState } from 'react';

function UserForm() {
  const [state, formAction, pending] = useActionState(createUser, null);

  return (
    
      
      
        {pending ? 'Creating...' : 'Create'}
      
      {state?.error && {state.error}}
    
  );
}

5. State Management

Zustand (Recommended)

import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';

interface UserStore {
  user: User | null;
  setUser: (user: User | null) => void;
  logout: () => void;
}

export const useUserStore = create()(
  devtools(
    persist(
      (set) => ({
        user: null,
        setUser: (user) => set({ user }),
        logout: () => set({ user: null }),
      }),
      { name: 'user-storage' }
    )
  )
);

// Usage
function Profile() {
  const { user, logout } = useUserStore();
  // ...
}

TanStack Query (Server State)

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

// Fetch
function useUsers() {
  return useQuery({
    queryKey: ['users'],
    queryFn: () => fetch('/api/users').then(r => r.json()),
    staleTime: 5 * 60 * 1000,  // 5 minutes
  });
}

// Mutate
function useCreateUser() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (user: NewUser) =>
      fetch('/api/users', { method: 'POST', body: JSON.stringify(user) }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['users'] });
    },
  });
}

6. Testing

Vitest (Recommended over Jest)

// vitest.config.ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./src/test/setup.ts'],
  },
});
// src/utils/calculate.test.ts
import { describe, it, expect } from 'vitest';
import { calculateTotal } from './calculate';

describe('calculateTotal', () => {
  it('sums items correctly', () => {
    const items = [
      { price: 10, quantity: 2 },
      { price: 5, quantity: 1 },
    ];
    expect(calculateTotal(items)).toBe(25);
  });

  it('handles empty cart', () => {
    expect(calculateTotal([])).toBe(0);
  });

  it('throws on negative price', () => {
    expect(() => calculateTotal([{ price: -1, quantity: 1 }]))
      .toThrow('Price must be positive');
  });
});

React Testing Library

import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { UserForm } from './UserForm';

it('submits form with user data', async () => {
  const onSubmit = vi.fn();
  render();

  fireEvent.change(screen.getByLabelText(/name/i), {
    target: { value: 'Alice' },
  });
  fireEvent.click(screen.getByRole('button', { name: /submit/i }));

  await waitFor(() => {
    expect(onSubmit).toHaveBeenCalledWith({ name: 'Alice' });
  });
});

Playwright (E2E)

// tests/e2e/login.spec.ts
import { test, expect } from '@playwright/test';

test('user can log in', async ({ page }) => {
  await page.goto('/login');
  await page.fill('[name="email"]', 'user@example.com');
  await page.fill('[name="password"]', 'password');
  await page.click('button[type="submit"]');
  await expect(page).toHaveURL('/dashboard');
});

7. Linting & Formatting

ESLint (Flat Config)

// eslint.config.js
import js from '@eslint/js';
import ts from 'typescript-eslint';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import prettier from 'eslint-config-prettier';

export default [
  js.configs.recommended,
  ...ts.configs.recommendedTypeChecked,
  react.configs.flat.recommended,
  reactHooks.configs['recommended-latest'],
  prettier,
  {
    languageOptions: {
      parserOptions: {
        project: './tsconfig.json',
      },
    },
    rules: {
      '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
      '@typescript-eslint/explicit-function-return-type': 'off',
      'react/react-in-jsx-scope': 'off',
      'react/prop-types': 'off',
    },
  },
];

Prettier

// .prettierrc
{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 100
}

8. Node.js Backend

Fastify (Recommended over Express)

import fastify from 'fastify';
import { z } from 'zod';

const app = fastify({ logger: true });

// Validation with Zod
const createUserSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
  age: z.number().min(0).optional(),
});

app.post('/users', async (request, reply) => {
  const body = createUserSchema.parse(request.body);
  const user = await db.users.create(body);
  reply.status(201).send(user);
});

// Error handler
app.setErrorHandler((error, request, reply) => {
  app.log.error(error);
  if (error instanceof z.ZodError) {
    reply.status(400).send({ error: 'Validation failed', details: error.errors });
    return;
  }
  reply.status(500).send({ error: 'Internal server error' });
});

await app.listen({ port: 3000 });

tRPC (Type-Safe APIs)

// server/router.ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';

const t = initTRPC.create();

export const appRouter = t.router({
  user: t.router({
    get: t.procedure
      .input(z.object({ id: z.string() }))
      .query(async ({ input }) => {
        return db.users.findById(input.id);
      }),
    create: t.procedure
      .input(z.object({ name: z.string(), email: z.string().email() }))
      .mutation(async ({ input }) => {
        return db.users.create(input);
      }),
  }),
});

export type AppRouter = typeof appRouter;

// client usage
import { createTRPCReact } from '@trpc/react-query';
const trpc = createTRPCReact();

// Fully type-safe: autocomplete works for 'user.get', 'user.create'
const { data } = trpc.user.get.useQuery({ id: '123' });

9. Integration with Other Skills

| This skill provides | Related skill | For deeper dive | |---|---|---| | React/Next.js patterns | python-development | FastAPI backend for full-stack | | Docker for JS apps | docker-containerization | Multi-stage builds, Node.js images | | K8s deployment | kubernetes-orchestration | Manifests for JS services | | Security | security-analysis | OWASP for web apps, auth patterns | | Testing | evolutionary-architecture | Fitness functions, architecture tests |


10. Bun Runtime Deep Dive

Bun is an all-in-one JavaScript runtime (faster than Node.js), bundler, test runner, and package manager.

Bun vs Node.js

| Feature | Bun | Node.js | |---|---|---| | Runtime speed | ~3x faster | Baseline | | Package manager | Built-in (bun install) | npm (external) | | Bundler | Built-in (bun build) | webpack/esbuild/rollup (external) | | Test runner | Built-in (bun test) | jest/vitest (external) | | TypeScript | Native (no ts-node) | Requires transpilation | | ESM/CJS | Both, seamless | ESM still experimental in some cases | | .env loading | Built-in (`Bun.env

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.