Getting Started
Get started with FoundryKit types for type-safe development
Getting Started
Learn how to use FoundryKit types to build type-safe applications with comprehensive TypeScript support.
Installation
Install the Types Package
Install the FoundryKit types package in your project.
npm install @foundrykit/types
Verify Installation
Check that the package is properly installed and accessible.
npm list @foundrykit/types
Prerequisites
Before using FoundryKit types, ensure you have the following:
- TypeScript (v4.9 or higher) - for type checking and inference
- Node.js (v18 or higher)
- React (v18 or higher) - for React-specific types
Check Your Environment
# Check TypeScript version
npx tsc --version
# Check Node.js version
node --version
# Check React version (if using React types)
npm list react
Quick Start
Basic Usage
Import and use types in your TypeScript project.
import type {
// Common utility types
Optional,
Required,
Nullable,
// React component types
ComponentProps,
ComponentRef,
// Event types
EventHandler,
ChangeHandler,
// API types
ApiResponse,
ApiError,
// Form types
FormData,
ValidationResult
} from '@foundrykit/types'
// Use types in your components
interface UserProfileProps {
user: Optional<User, 'avatar' | 'bio'>
onUpdate: EventHandler<User>
className?: string
}
export function UserProfile({ user, onUpdate, className }: UserProfileProps) {
// Type-safe component implementation
return (
<div className={className}>
<h1>{user.name}</h1>
{user.avatar && <img src={user.avatar} alt="Avatar" />}
{user.bio && <p>{user.bio}</p>}
</div>
)
}
TypeScript Configuration
Configure TypeScript for optimal type checking with FoundryKit types.
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
// Strict type checking
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true,
// Path mapping for cleaner imports
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/types/*": ["./src/types/*"]
}
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
Package Structure
The types package is organized into logical modules for different use cases.
Type Categories
Utility Types
Common utility types for data manipulation and transformation.
import type {
Optional,
Required,
Nullable,
NonNullable,
DeepPartial,
DeepRequired,
Prettify
} from '@foundrykit/types'
// Make specific properties optional
type UserWithOptionalFields = Optional<User, 'avatar' | 'bio'>
// Make specific properties required
type UserWithRequiredFields = Required<Partial<User>, 'id' | 'name'>
// Nullable and non-nullable types
type NullableString = Nullable<string>
type DefiniteString = NonNullable<string | null | undefined>
// Deep partial for nested objects
type PartialUserProfile = DeepPartial<{
user: {
id: string
profile: {
name: string
settings: {
theme: string
notifications: boolean
}
}
}
}>
// Prettify complex intersection types
type CleanType = Prettify<BaseProps & ExtendedProps & UtilityProps>
React Types
Comprehensive React component and hook types.
import type {
ComponentProps,
ComponentRef,
ForwardRefComponent,
PolymorphicComponent,
WithChildren,
WithClassName
} from '@foundrykit/types'
// Component props with common patterns
interface ButtonProps extends ComponentProps<'button'>, WithClassName {
variant?: 'primary' | 'secondary' | 'danger'
size?: 'sm' | 'md' | 'lg'
loading?: boolean
}
// Forward ref component
const Button: ForwardRefComponent<'button', ButtonProps> = forwardRef(
({ className, variant = 'primary', size = 'md', loading, children, ...props }, ref) => {
return (
<button
ref={ref}
className={cn('btn', `btn-${variant}`, `btn-${size}`, className)}
disabled={loading}
{...props}
>
{loading ? 'Loading...' : children}
</button>
)
}
)
// Polymorphic component (can render as different elements)
interface CardProps extends WithChildren, WithClassName {
variant?: 'default' | 'elevated'
padding?: 'none' | 'sm' | 'md' | 'lg'
}
const Card: PolymorphicComponent<'div', CardProps> = ({
as: Component = 'div',
variant = 'default',
padding = 'md',
className,
children,
...props
}) => {
return (
<Component
className={cn('card', `card-${variant}`, `card-padding-${padding}`, className)}
{...props}
>
{children}
</Component>
)
}
Event Types
Type-safe event handling.
import type {
EventHandler,
ChangeHandler,
SubmitHandler,
KeyboardHandler,
MouseHandler
} from '@foundrykit/types'
interface FormProps {
onSubmit: SubmitHandler<FormData>
onChange: ChangeHandler<string>
onKeyDown: KeyboardHandler
onClick: MouseHandler
}
export function SearchForm({ onSubmit, onChange, onKeyDown, onClick }: FormProps) {
const handleSubmit: SubmitHandler<FormData> = (data, event) => {
event.preventDefault()
onSubmit(data, event)
}
const handleChange: ChangeHandler<string> = (value, event) => {
onChange(value, event)
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
onChange={(e) => handleChange(e.target.value, e)}
onKeyDown={onKeyDown}
onClick={onClick}
/>
<button type="submit">Search</button>
</form>
)
}
API Types
Standardized API request and response types.
import type {
ApiResponse,
ApiError,
PaginatedResponse,
ApiEndpoint,
HttpMethod
} from '@foundrykit/types'
// API response wrapper
interface UserApiResponse extends ApiResponse<User> {
user: User
}
// Paginated API response
interface UsersListResponse extends PaginatedResponse<User> {
users: User[]
}
// API error handling
interface CustomApiError extends ApiError {
field?: string
code: 'VALIDATION_ERROR' | 'NOT_FOUND' | 'UNAUTHORIZED'
}
// API endpoint configuration
interface UserEndpoints {
getUser: ApiEndpoint<{ id: string }, UserApiResponse>
getUsers: ApiEndpoint<{ page?: number; limit?: number }, UsersListResponse>
createUser: ApiEndpoint<CreateUserRequest, UserApiResponse>
updateUser: ApiEndpoint<{ id: string } & UpdateUserRequest, UserApiResponse>
deleteUser: ApiEndpoint<{ id: string }, { success: boolean }>
}
// Usage in API client
class UserApiClient {
async getUser(params: Parameters<UserEndpoints['getUser']>[0]) {
const response = await fetch(`/api/users/${params.id}`)
return response.json() as Promise<UserApiResponse>
}
async getUsers(params: Parameters<UserEndpoints['getUsers']>[0] = {}) {
const searchParams = new URLSearchParams(
Object.entries(params).map(([key, value]) => [key, String(value)])
)
const response = await fetch(`/api/users?${searchParams}`)
return response.json() as Promise<UsersListResponse>
}
}
Form Types
Comprehensive form handling types.
import type {
FormData,
FormField,
ValidationResult,
FormErrors,
FieldValidator,
FormState
} from '@foundrykit/types'
// Form field configuration
interface UserFormFields {
name: FormField<string, { required: true; minLength: 2 }>
email: FormField<string, { required: true; pattern: 'email' }>
age: FormField<number, { required: true; min: 18; max: 120 }>
bio: FormField<string, { required: false; maxLength: 500 }>
}
// Form data type
type UserFormData = FormData<UserFormFields>
// Validation result
interface UserValidationResult extends ValidationResult<UserFormData> {
isValid: boolean
errors: FormErrors<UserFormData>
data: UserFormData | null
}
// Custom validators
const nameValidator: FieldValidator<string> = (value) => {
if (!value || value.length < 2) {
return { isValid: false, error: 'Name must be at least 2 characters' }
}
return { isValid: true }
}
const emailValidator: FieldValidator<string> = (value) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!emailRegex.test(value)) {
return { isValid: false, error: 'Please enter a valid email address' }
}
return { isValid: true }
}
// Form state management
interface UserFormState extends FormState<UserFormData> {
data: UserFormData
errors: FormErrors<UserFormData>
isSubmitting: boolean
isValid: boolean
isDirty: boolean
}
Type Guards and Predicates
Use type guards for runtime type checking.
import type { TypeGuard, Predicate } from '@foundrykit/types'
import { isString, isNumber, isObject, hasProperty } from '@foundrykit/types/guards'
// Built-in type guards
function processValue(value: unknown) {
if (isString(value)) {
// TypeScript knows value is string here
return value.toUpperCase()
}
if (isNumber(value)) {
// TypeScript knows value is number here
return value.toFixed(2)
}
if (isObject(value) && hasProperty(value, 'name')) {
// TypeScript knows value has a 'name' property
return value.name
}
return 'Unknown value'
}
// Custom type guards
interface User {
id: string
name: string
email: string
}
const isUser: TypeGuard<User> = (value): value is User => {
return (
isObject(value) &&
hasProperty(value, 'id') && isString(value.id) &&
hasProperty(value, 'name') && isString(value.name) &&
hasProperty(value, 'email') && isString(value.email)
)
}
// Usage with type narrowing
function handleUserData(data: unknown) {
if (isUser(data)) {
// TypeScript knows data is User here
console.log(`Hello, ${data.name}!`)
console.log(`Email: ${data.email}`)
} else {
console.error('Invalid user data')
}
}
Integration Examples
React Component with Types
import React, { useState } from 'react'
import type {
ComponentProps,
WithChildren,
WithClassName,
EventHandler,
ChangeHandler,
Optional
} from '@foundrykit/types'
// Base component props
interface BaseCardProps extends WithChildren, WithClassName {
title?: string
variant?: 'default' | 'elevated' | 'outlined'
padding?: 'none' | 'sm' | 'md' | 'lg'
}
// Interactive card props
interface InteractiveCardProps extends BaseCardProps {
onClick?: EventHandler<MouseEvent>
onHover?: EventHandler<MouseEvent>
disabled?: boolean
}
// Form card props
interface FormCardProps extends BaseCardProps {
onSubmit: SubmitHandler<FormData>
loading?: boolean
}
// Generic card component
function Card<T extends BaseCardProps>({
title,
variant = 'default',
padding = 'md',
className,
children,
...props
}: T) {
return (
<div
className={cn(
'card',
`card-${variant}`,
`card-padding-${padding}`,
className
)}
{...props}
>
{title && <div className="card-header">{title}</div>}
<div className="card-content">{children}</div>
</div>
)
}
// Usage examples
export function CardExamples() {
return (
<div className="space-y-4">
{/* Basic card */}
<Card title="Basic Card" variant="default">
<p>This is a basic card.</p>
</Card>
{/* Interactive card */}
<Card
title="Interactive Card"
variant="elevated"
onClick={(event) => console.log('Card clicked:', event)}
className="cursor-pointer"
>
<p>Click this card!</p>
</Card>
{/* Form card */}
<Card
title="Form Card"
variant="outlined"
onSubmit={(data, event) => {
event.preventDefault()
console.log('Form submitted:', data)
}}
>
<form>
<input type="text" placeholder="Enter text..." />
<button type="submit">Submit</button>
</form>
</Card>
</div>
)
}
API Integration with Types
import type {
ApiResponse,
ApiError,
PaginatedResponse,
HttpMethod
} from '@foundrykit/types'
// API client with full type safety
class TypedApiClient {
private baseUrl: string
constructor(baseUrl: string) {
this.baseUrl = baseUrl
}
private async request<TResponse>(
method: HttpMethod,
endpoint: string,
data?: unknown
): Promise<TResponse> {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method,
headers: {
'Content-Type': 'application/json',
},
body: data ? JSON.stringify(data) : undefined,
})
if (!response.ok) {
const error: ApiError = await response.json()
throw new Error(error.message)
}
return response.json()
}
// Typed API methods
async getUsers(params?: {
page?: number
limit?: number
search?: string
}): Promise<PaginatedResponse<User>> {
const searchParams = new URLSearchParams()
if (params?.page) searchParams.set('page', String(params.page))
if (params?.limit) searchParams.set('limit', String(params.limit))
if (params?.search) searchParams.set('search', params.search)
const queryString = searchParams.toString()
const endpoint = `/users${queryString ? `?${queryString}` : ''}`
return this.request<PaginatedResponse<User>>('GET', endpoint)
}
async getUser(id: string): Promise<ApiResponse<User>> {
return this.request<ApiResponse<User>>('GET', `/users/${id}`)
}
async createUser(userData: CreateUserRequest): Promise<ApiResponse<User>> {
return this.request<ApiResponse<User>>('POST', '/users', userData)
}
async updateUser(
id: string,
userData: UpdateUserRequest
): Promise<ApiResponse<User>> {
return this.request<ApiResponse<User>>('PUT', `/users/${id}`, userData)
}
async deleteUser(id: string): Promise<{ success: boolean }> {
return this.request<{ success: boolean }>('DELETE', `/users/${id}`)
}
}
// Usage with full type safety
const apiClient = new TypedApiClient('/api')
async function loadUserData() {
try {
// All parameters and return types are fully typed
const usersResponse = await apiClient.getUsers({
page: 1,
limit: 10,
search: 'john'
})
console.log('Users:', usersResponse.data)
console.log('Total:', usersResponse.pagination.total)
if (usersResponse.data.length > 0) {
const firstUser = usersResponse.data[0]
const userDetails = await apiClient.getUser(firstUser.id)
console.log('User details:', userDetails.data)
}
} catch (error) {
console.error('Failed to load users:', error)
}
}
Advanced Usage
Generic Type Utilities
import type { DeepPartial, DeepRequired, KeysOfType } from '@foundrykit/types'
// Extract keys of specific types
interface UserPreferences {
theme: 'light' | 'dark'
notifications: boolean
language: string
fontSize: number
}
type StringKeys = KeysOfType<UserPreferences, string> // 'theme' | 'language'
type BooleanKeys = KeysOfType<UserPreferences, boolean> // 'notifications'
type NumberKeys = KeysOfType<UserPreferences, number> // 'fontSize'
// Deep manipulation of nested types
interface NestedConfig {
app: {
name: string
version: string
features: {
darkMode: boolean
analytics: boolean
notifications: {
email: boolean
push: boolean
sms: boolean
}
}
}
user: {
profile: {
name: string
email: string
}
preferences: UserPreferences
}
}
// Make all properties optional deeply
type PartialConfig = DeepPartial<NestedConfig>
// Make all properties required deeply
type RequiredConfig = DeepRequired<PartialConfig>
TypeScript Integration
Strict Type Checking
Enable strict type checking for maximum type safety.
{
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"useUnknownInCatchVariables": true,
"noImplicitOverride": true
}
}
Path Mapping
Set up path mapping for cleaner imports.
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/types": ["@foundrykit/types"],
"@/components/*": ["./src/components/*"],
"@/utils/*": ["./src/utils/*"]
}
}
}
Next Steps
- Explore type definitions reference for detailed type documentation
- Learn about custom type patterns for advanced usage
- Review integration guide for framework-specific usage
- Check out best practices for optimal type usage