Type Safety

End-to-end type safety with TypeScript, Prisma, and Next.js in the went framework.

TypeScript Configuration

tsconfig.json

The went framework comes with a pre-configured TypeScript setup optimized for Next.js 15:

{
  "compilerOptions": {
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [{ "name": "next" }],
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

Database Type Safety with Prisma

Generated Types

Prisma automatically generates TypeScript types from your database schema:

import { PrismaClient, User, Order } from '@/generated/prisma'

// TypeScript knows the exact shape of your data
const user: User = await prisma.user.findUnique({
  where: { id: 'user-id' }
})

// Intellisense and type checking for all fields
console.log(user.email)    // ✅ TypeScript knows this exists
console.log(user.invalid)  // ❌ TypeScript error
Query Type Safety

Prisma provides type-safe database queries with full IntelliSense support:

// Type-safe queries with autocomplete
const userWithOrders = await prisma.user.findMany({
  where: {
    email: { contains: '@example.com' }  // ✅ Valid
    // invalidField: 'value'              // ❌ TypeScript error
  },
  include: {
    orders: {
      where: { status: 'completed' }
    }
  }
})

// Return type is automatically inferred
// userWithOrders: (User & { orders: Order[] })[]

API Route Type Safety

Next.js API Routes

The went framework provides full type safety for API routes through TypeScript integration with Next.js 15 App Router. All request and response types are properly typed, ensuring compile-time safety.

Route handlers automatically infer parameter types from dynamic routes, and Prisma integration ensures database operations are fully type-safe from the API layer through to the database schema.

Component Type Safety

Props Interface

Define strict interfaces for React component props:

// components/UserCard.tsx
import { User } from '@/generated/prisma'

interface UserCardProps {
  user: User
  onEdit?: (userId: string) => void
  showActions?: boolean
}

export function UserCard({ user, onEdit, showActions = true }: UserCardProps) {
  return (
    <div className="card">
      <h3>{user.email}</h3>
      {showActions && (
        <button onClick={() => onEdit?.(user.id)}>
          Edit User
        </button>
      )}
    </div>
  )
}
Server Components

Type-safe server components with async data fetching:

// app/users/page.tsx
import { prisma } from '@/lib/db'
import { UserCard } from '@/components/UserCard'

interface PageProps {
  searchParams: { search?: string }
}

export default async function UsersPage({ searchParams }: PageProps) {
  const users = await prisma.user.findMany({
    where: searchParams.search ? {
      email: { contains: searchParams.search }
    } : undefined
  })

  return (
    <div>
      {users.map(user => (
        <UserCard key={user.id} user={user} />
      ))}
    </div>
  )
}

Form Type Safety

Server Actions with TypeScript

Create type-safe form actions with validation:

// lib/actions.ts
'use server'

import { z } from 'zod'
import { prisma } from '@/lib/db'

const CreateUserSchema = z.object({
  email: z.string().email('Invalid email address')
})

type CreateUserData = z.infer<typeof CreateUserSchema>

export async function createUser(data: CreateUserData) {
  const validated = CreateUserSchema.parse(data)
  
  const user = await prisma.user.create({
    data: { email: validated.email }
  })
  
  return { success: true, user }
}

// Usage in component
export function UserForm() {
  return (
    <form action={createUser}>
      <input name="email" type="email" required />
      <button type="submit">Create User</button>
    </form>
  )
}

Type Safety Best Practices

Strict TypeScript

  • • Enable strict mode in tsconfig.json
  • • Use noImplicitAny and noImplicitReturns
  • • Avoid any type - use unknown instead
  • • Enable exactOptionalPropertyTypes

Database Types

  • • Use Prisma generated types everywhere
  • • Run went db generate after schema changes
  • • Use Prisma.UserSelect for partial selections
  • • Leverage conditional types for includes

API Safety

  • • Define request/response interfaces
  • • Use zod for runtime validation
  • • Type your server actions properly
  • • Handle errors with typed responses

Development Workflow

  • • Use TypeScript in strict mode
  • • Set up ESLint with TypeScript rules
  • • Run type checking in CI/CD pipeline
  • • Use IDE with TypeScript support

Type Generation Commands

went CLI Type Commands
went db generate

Generate TypeScript types from Prisma schema

npm run build

Type check and build the application

npx tsc --noEmit

Type check without building (useful for CI)

Next Steps

Continue your journey with Went: