TypeScript Support
Headwind is built with TypeScript and provides full type safety for configuration, APIs, and custom extensions.
Type-Safe Configuration
Use TypeScript for your configuration file to get autocompletion and type checking:
// headwind.config.ts
import type { HeadwindOptions } from 'headwind'
const config = {
content: ['./src/**/*.{html,js,ts,jsx,tsx}'],
output: './dist/headwind.css',
minify: false,
theme: {
colors: {
primary: '#3b82f6',
secondary: '#8b5cf6',
},
},
shortcuts: {
btn: 'px-4 py-2 rounded font-semibold',
},
} satisfies HeadwindOptions
export default configType Checking
The satisfies keyword provides type checking while preserving literal types:
import type { HeadwindOptions } from 'headwind'
// ✅ Type-safe with autocompletion
const config = {
content: ['./src/**/*.tsx'],
output: './dist/headwind.css',
minify: true,
} satisfies HeadwindOptions
// ❌ Type error - unknown property
const badConfig = {
content: ['./src/**/*.tsx'],
outputPath: './dist/headwind.css', // Error: 'outputPath' does not exist
// ^^^^^^^^ Property error
} satisfies HeadwindOptionsAvailable Types
HeadwindConfig
Main configuration interface:
interface HeadwindConfig {
content: string[]
output: string
minify: boolean
watch: boolean
verbose?: boolean
theme: Theme
shortcuts: Record<string, string | string[]>
rules: CustomRule[]
variants: VariantConfig
safelist: string[]
blocklist: string[]
preflights: Preflight[]
presets: Preset[]
compileClass?: CompileClassConfig
}Theme
Theme customization types:
interface Theme {
colors: Record<string, string | Record<string, string>>
spacing: Record<string, string>
fontSize: Record<string, [string, { lineHeight: string }]>
fontFamily: Record<string, string[]>
screens: Record<string, string>
borderRadius: Record<string, string>
boxShadow: Record<string, string>
}CompileClassConfig
Compile class configuration:
interface CompileClassConfig {
enabled?: boolean
trigger?: string
classPrefix?: string
layer?: string
}CustomRule
Custom rule type:
type CustomRule = [
RegExp,
(match: RegExpMatchArray) => Record<string, string> | undefined
]Autocompletion
Get IntelliSense and autocompletion in your IDE:
VSCode
- Install the TypeScript extension (comes pre-installed)
- Create
headwind.config.tswith the type import:
import type { HeadwindOptions } from 'headwind'
const config = {
// Press Ctrl+Space here for autocompletion
theme: {
// Autocomplete shows all theme options
},
} satisfies HeadwindOptionsTheme Autocompletion
const config = {
theme: {
// Autocomplete shows: colors, spacing, fontSize, etc.
colors: {
// Type 'primary' and get suggestions
},
fontSize: {
// See all font size options
},
},
} satisfies HeadwindOptionsShortcuts Autocompletion
const config = {
shortcuts: {
// Autocomplete for shortcut names
'btn': 'px-4 py-2 rounded',
'btn-primary': 'btn bg-blue-500', // Autocomplete shows existing shortcuts
},
} satisfies HeadwindOptionsType Inference
TypeScript infers types from your configuration:
const config = {
theme: {
colors: {
primary: '#3b82f6',
brand: {
50: '#f0f9ff',
100: '#e0f2fe',
500: '#0ea5e9',
},
},
},
} satisfies HeadwindOptions
// TypeScript knows:
// config.theme.colors.primary is string
// config.theme.colors.brand is Record<string, string>Programmatic API Types
Build Function
import type { BuildResult, HeadwindConfig } from 'headwind'
import { build } from 'headwind'
const result: BuildResult = await build({
content: ['./src/**/*.tsx'],
output: './dist/headwind.css',
} as HeadwindConfig)
// result.css: string
// result.classes: Set<string>
// result.duration: number
// result.compiledClasses?: Map<string, { className: string; utilities: string[] }>
// result.transformedFiles?: Map<string, string>BuildResult Type
interface BuildResult {
css: string
classes: Set<string>
duration: number
compiledClasses?: Map<string, { className: string, utilities: string[] }>
transformedFiles?: Map<string, string>
}Using with async/await
import { build, buildAndWrite } from 'headwind'
async function buildStyles() {
// With build
const result = await build({
content: ['./src/**/*.tsx'],
output: './dist/headwind.css',
minify: true,
})
console.log(`Generated ${result.classes.size} classes`)
// With buildAndWrite
await buildAndWrite({
content: ['./src/**/*.tsx'],
output: './dist/headwind.css',
minify: true,
})
}Custom Rules with Types
Define type-safe custom rules:
import type { CustomRule, HeadwindConfig } from 'headwind'
const customRules: CustomRule[] = [
// Pattern and handler with types
[
/^custom-(\w+)$/,
(match: RegExpMatchArray): Record<string, string> | undefined => {
const value = match[1]
return {
'custom-property': value,
}
},
],
]
const config = {
rules: customRules,
} satisfies HeadwindOptionsPreset Types
Create type-safe presets:
import type { Preset, Theme } from 'headwind'
const myPreset: Preset = {
name: 'my-design-system',
theme: {
colors: {
primary: '#3b82f6',
secondary: '#8b5cf6',
},
spacing: {
sm: '0.5rem',
md: '1rem',
lg: '2rem',
},
},
shortcuts: {
btn: 'px-4 py-2 rounded font-semibold',
},
rules: [
[/^custom-/, () => ({ color: 'red' })],
],
}
// Use in config
const config = {
presets: [myPreset],
}Extending Types
Custom Theme Values
Extend the theme with custom properties:
import type { HeadwindOptions, Theme } from 'headwind'
interface CustomTheme extends Theme {
customSpacing: Record<string, string>
customColors: Record<string, string>
}
const config = {
theme: {
customSpacing: {
'xs': '0.25rem',
'2xs': '0.125rem',
},
customColors: {
brand: '#ff6b6b',
},
} as CustomTheme,
} satisfies HeadwindOptionsCustom Config
Create a custom config interface:
import type { HeadwindOptions } from 'headwind'
interface MyConfig extends Partial<HeadwindConfig> {
// Add custom properties
customOption?: boolean
metadata?: {
version: string
author: string
}
}
const config: MyConfig = {
content: ['./src/**/*.tsx'],
output: './dist/headwind.css',
customOption: true,
metadata: {
version: '1.0.0',
author: 'Your Name',
},
}Type Guards
Use type guards for runtime type checking:
import type { HeadwindOptions } from 'headwind'
function isValidConfig(config: unknown): config is HeadwindConfig {
return (
typeof config === 'object'
&& config !== null
&& 'content' in config
&& 'output' in config
&& Array.isArray((config as HeadwindConfig).content)
)
}
// Usage
const config: unknown = loadConfigFromSomewhere()
if (isValidConfig(config)) {
// TypeScript knows config is HeadwindConfig
console.log(config.content)
}Generics
Use generics for flexible, type-safe functions:
import type { HeadwindOptions } from 'headwind'
function createConfig<T extends Partial<HeadwindConfig>>(config: T): T {
return {
...config,
// Add defaults while preserving original types
}
}
const config = createConfig({
content: ['./src/**/*.tsx'],
theme: {
colors: {
primary: '#3b82f6',
},
},
})
// TypeScript infers the exact typeModule Augmentation
Extend Headwind types globally:
// Now use in config
import type { HeadwindOptions } from 'headwind'
// types/headwind.d.ts
import 'headwind'
declare module 'headwind' {
interface HeadwindConfig {
// Add your custom properties
customFeature?: {
enabled: boolean
options: Record<string, any>
}
}
interface Theme {
// Extend theme
customScale?: Record<string, string>
}
}
const config = {
customFeature: {
enabled: true,
options: {},
},
theme: {
customScale: {
xs: '0.5rem',
},
},
} satisfies HeadwindOptionsIntegration with Build Tools
Vite
import type { HeadwindOptions } from 'headwind'
import { build } from 'headwind'
// vite.config.ts
import { defineConfig } from 'vite'
const headwindConfig: HeadwindConfig = {
content: ['./src/**/*.tsx'],
output: './dist/headwind.css',
minify: true,
}
export default defineConfig({
plugins: [
{
name: 'headwind',
async buildStart() {
await build(headwindConfig)
},
},
],
})Next.js
import type { HeadwindOptions } from 'headwind'
// next.config.ts
import type { NextConfig } from 'next'
import { buildAndWrite } from 'headwind'
const headwindConfig: HeadwindConfig = {
content: ['./src/**/*.tsx', './app/**/*.tsx'],
output: './public/headwind.css',
minify: process.env.NODE_ENV === 'production',
}
const nextConfig: NextConfig = {
webpack: (config, { isServer }) => {
if (!isServer) {
buildAndWrite(headwindConfig)
}
return config
},
}
export default nextConfigType Utilities
Headwind provides useful type utilities:
import type {
CustomRule,
HeadwindConfig,
ParsedClass,
Preset,
Theme,
} from 'headwind'
// Extract specific types
type ConfigColors = Theme['colors']
type ConfigSpacing = Theme['spacing']
// Use utility types
type RequiredConfig = Required<HeadwindConfig>
type PartialTheme = Partial<Theme>Best Practices
1. Always Use Type Imports
// ✅ Type-only import
import type { HeadwindOptions } from 'headwind'
// ❌ Value import (unnecessary)
import { HeadwindConfig } from 'headwind'2. Use satisfies for Validation
// ✅ Validates types while preserving literals
const config = {
content: ['./src/**/*.tsx'],
} satisfies HeadwindOptions
// ❌ Loses literal types
const config: Partial<HeadwindConfig> = {
content: ['./src/**/*.tsx'],
}3. Separate Type Definitions
// types/headwind.ts
import type { HeadwindOptions, Preset } from 'headwind'
// headwind.config.ts
import type { MyConfig } from './types/headwind'
export interface MyCustomPreset extends Preset {
customOption: boolean
}
export interface MyConfig extends Partial<HeadwindConfig> {
presets: MyCustomPreset[]
}
const config: MyConfig = {
// ...
}4. Document Custom Types
/**
* Custom theme with extended color palette
*/
interface CustomTheme extends Theme {
/**
* Brand colors for the application
*/
brandColors: {
primary: string
secondary: string
accent: string
}
}Troubleshooting
Type Errors
Problem: TypeScript errors in config
// Error: Type 'string' is not assignable to type 'string[]'
const config = {
content: './src/**/*.tsx', // Should be array
} satisfies HeadwindOptionsSolution:
const config = {
content: ['./src/**/*.tsx'], // Correct: array
} satisfies HeadwindOptionsMissing Types
Problem: Cannot find type definitions
Solution:
# Ensure TypeScript is installed
bun add --dev typescript
# Ensure types are imported
import type { HeadwindOptions } from 'headwind'Autocomplete Not Working
Problem: No autocompletion in IDE
Solutions:
Restart TypeScript server
Check tsconfig.json includes the config file
Ensure proper imports:
typescriptimport type { HeadwindOptions } from 'headwind'
Related
- Configuration - Full configuration guide
- Custom Rules - Creating custom utilities
- Presets - Reusable configurations
- API Reference - Programmatic API