This skill should be used when the user asks to "setup TypeScript", "TypeScript types", "generics", "type inference", "interfaces", "type safety", or works with TypeScript development and type system.
TypeScript is a strongly typed programming language that builds on JavaScript.
Basic types:
// Primitives
let name: string = 'John'
let age: number = 30
let isActive: boolean = true
let nothing: null = null
let notDefined: undefined = undefined
// Arrays
let numbers: number[] = [1, 2, 3]
let names: Array<string> = ['Alice', 'Bob']
// Tuples
let person: [string, number] = ['John', 30]
// Objects
let user: { name: string; age: number } = {
name: 'John',
age: 30,
}
// Union types
let id: string | number = 'abc123'
id = 123
// Literal types
let direction: 'north' | 'south' | 'east' | 'west' = 'north'
// Any (avoid when possible)
let anything: any = 4
anything = 'string'
// Unknown (safer than any)
let unknownValue: unknown = 4
if (typeof unknownValue === 'number') {
unknownValue.toFixed()
}
// Void (for functions with no return)
function logMessage(message: string): void {
console.log(message)
}
// Never (for functions that never return)
function throwError(message: string): never {
throw new Error(message)
}
Interface:
interface User {
id: number
name: string
email: string
age?: number // Optional
readonly createdAt: Date // Read-only
}
// Extending interfaces
interface Admin extends User {
role: 'admin' | 'superadmin'
permissions: string[]
}
// Interface with method
interface Logger {
log(message: string): void
error(message: string): void
}
Type alias:
type User = {
id: number
name: string
email: string
}
// Union type
type Status = 'pending' | 'active' | 'inactive'
// Intersection type
type AdminUser = User & {
role: 'admin'
}
// Function type
type Handler = (event: Event) => void
// Mapped type
type ReadonlyUser = {
readonly [K in keyof User]: User[K]
}
// Conditional type
type NonNullable<T> = T extends null | undefined ? never : T
Interface vs Type:
interface for object shapes that may be extendedtype for unions, tuples, and mapped typesinterface supports declaration mergingBasic generic:
function identity<T>(arg: T): T {
return arg
}
const num = identity<number>(42)
const str = identity<string>('hello')
const inferred = identity(42) // Type inferred
Generic with constraints:
interface HasLength {
length: number
}
function logLength<T extends HasLength>(arg: T): T {
console.log(arg.length)
return arg
}
logLength('string')
logLength([1, 2, 3])
logLength({ length: 10 })
Generic interfaces:
interface Container<T> {
value: T
getValue(): T
setValue(value: T): void
}
const numberContainer: Container<number> = {
value: 42,
getValue() {
return this.value
},
setValue(value) {
this.value = value
},
}
Generic classes:
class Stack<T> {
private items: T[] = []
push(item: T): void {
this.items.push(item)
}
pop(): T | undefined {
return this.items.pop()
}
peek(): T | undefined {
return this.items[this.items.length - 1]
}
}
const numberStack = new Stack<number>()
numberStack.push(1)
numberStack.push(2)
const top = numberStack.pop() // number | undefined
Generic with default:
interface ApiResponse<T = unknown> {
data: T
status: number
message: string
}
type UserResponse = ApiResponse<User>
type GenericResponse = ApiResponse // Uses unknown as default
Utility types with generics:
// Partial - all properties optional
type PartialUser = Partial<User>
// Required - all properties required
type RequiredUser = Required<PartialUser>
// Pick - select specific properties
type UserPreview = Pick<User, 'id' | 'name'>
// Omit - exclude specific properties
type UserWithoutEmail = Omit<User, 'email'>
// Record - key-value pairs
type UsersById = Record<string, User>
// Exclude / Extract
type NonString = Exclude<string | number | boolean, string>
type OnlyString = Extract<string | number | boolean, string>
// ReturnType
type HandlerReturn = ReturnType<() => string>
// Parameters
type HandlerParams = Parameters<(name: string, age: number) => void>
Conditional types:
type IsString<T> = T extends string ? true : false
type A = IsString<string> // true
type B = IsString<number> // false
Template literal types:
type EventName<T extends string> = `on${Capitalize<T>}`
type ClickEvent = EventName<'click'> // 'onClick'
type HttpMethod = 'get' | 'post' | 'put' | 'delete'
type Endpoint = `/api/${string}/${HttpMethod}`
Inference with infer:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never
type Fn = () => string
type R = ReturnType<Fn> // string
Function signatures:
// Named function
function add(a: number, b: number): number {
return a + b
}
// Arrow function
const multiply = (a: number, b: number): number => a * b
// Optional parameters
function greet(name: string, greeting?: string): string {
return `${greeting ?? 'Hello'}, ${name}!`
}
// Default parameters
function createUser(name: string, age: number = 18): User {
return { id: 1, name, age }
}
// Rest parameters
function sum(...numbers: number[]): number {
return numbers.reduce((a, b) => a + b, 0)
}
// Overloads
function process(input: string): string
function process(input: number): number
function process(input: string | number): string | number {
if (typeof input === 'string') {
return input.toUpperCase()
}
return input * 2
}
Function types:
type Comparator<T> = (a: T, b: T) => number
const numberComparator: Comparator<number> = (a, b) => a - b
// Callback type
type Callback<T> = (result: T) => void
function fetchData<T>(url: string, callback: Callback<T>): void {
// Implementation
}
class Animal {
protected name: string
private age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
move(distance: number): void {
console.log(`${this.name} moved ${distance}m`)
}
getAge(): number {
return this.age
}
}
class Dog extends Animal {
constructor(name: string, age: number, private breed: string) {
super(name, age)
}
bark(): void {
console.log(`${this.name} says woof!`)
}
// Getter/setter
get info(): string {
return `${this.name} is a ${this.breed}`
}
// Static member
static isDog(animal: Animal): animal is Dog {
return animal instanceof Dog
}
}
// Abstract class
abstract class Shape {
abstract area(): number
describe(): void {
console.log(`Area: ${this.area()}`)
}
}
class Circle extends Shape {
constructor(private radius: number) {
super()
}
area(): number {
return Math.PI * this.radius ** 2
}
}
// Interface implementation
interface Drawable {
draw(): void
}
class Canvas implements Drawable {
draw(): void {
console.log('Drawing on canvas')
}
}
// typeof guard
function process(value: string | number) {
if (typeof value === 'string') {
return value.toUpperCase() // string
}
return value.toFixed(2) // number
}
// instanceof guard
function handleError(error: Error | string) {
if (error instanceof Error) {
return error.message
}
return error
}
// in guard
interface Car {
drive(): void
}
interface Boat {
sail(): void
}
function move(vehicle: Car | Boat) {
if ('drive' in vehicle) {
vehicle.drive()
} else {
vehicle.sail()
}
}
// Custom type guard
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every(item => typeof item === 'string')
}
// Discriminated unions
interface Square {
kind: 'square'
size: number
}
interface Circle {
kind: 'circle'
radius: number
}
type Shape = Square | Circle
function getArea(shape: Shape): number {
switch (shape.kind) {
case 'square':
return shape.size ** 2
case 'circle':
return Math.PI * shape.radius ** 2
}
}
tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
references/typescript-patterns.md - Common type patternsexamples/type-definitions/ - Type definition examples