Type Definitions Reference
Complete reference for all FoundryKit type definitions
Type Definitions Reference
Complete reference for all FoundryKit type definitions, organized by category with detailed examples and usage patterns.
Utility Types
Core Utility Types
Essential utility types for data manipulation and transformation.
Optional<T, K>
Make specific properties of a type optional.
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
// Usage
interface User {
id: string
name: string
email: string
avatar: string
bio: string
}
// Make avatar and bio optional
type UserWithOptionalFields = Optional<User, 'avatar' | 'bio'>
// Result: { id: string; name: string; email: string; avatar?: string; bio?: string }
// Example usage
function createUser(userData: UserWithOptionalFields): User {
return {
avatar: '/default-avatar.png',
bio: '',
...userData
}
}
Required<T, K>
Make specific properties of a type required.
type Required<T, K extends keyof T> = T & Required<Pick<T, K>>
// Usage
interface PartialUser {
id?: string
name?: string
email?: string
avatar?: string
}
// Make id and name required
type UserWithRequiredFields = Required<PartialUser, 'id' | 'name'>
// Result: { id: string; name: string; email?: string; avatar?: string }
Nullable<T>
Allow a type to be null.
type Nullable<T> = T | null
// Usage
type NullableString = Nullable<string> // string | null
type NullableUser = Nullable<User> // User | null
function findUser(id: string): NullableUser {
const user = users.find(u => u.id === id)
return user || null
}
NonNullable<T>
Remove null and undefined from a type.
type NonNullable<T> = T extends null | undefined ? never : T
// Usage
type DefiniteString = NonNullable<string | null | undefined> // string
type DefiniteUser = NonNullable<User | null | undefined> // User
function processUser(user: User | null | undefined) {
if (user) {
// TypeScript knows user is NonNullable<User> here
handleDefiniteUser(user)
}
}
function handleDefiniteUser(user: NonNullable<User>) {
// user is guaranteed to be defined
console.log(user.name)
}
Deep Utility Types
Advanced utility types for nested object manipulation.
DeepPartial<T>
Make all properties of a type optional recursively.
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]
}
// Usage
interface NestedConfig {
app: {
name: string
version: string
features: {
darkMode: boolean
analytics: boolean
}
}
user: {
profile: {
name: string
email: string
}
}
}
type PartialConfig = DeepPartial<NestedConfig>
// Result: All properties are optional at every level
const config: PartialConfig = {
app: {
name: 'MyApp' // version and features are optional
}
// user is completely optional
}
DeepRequired<T>
Make all properties of a type required recursively.
type DeepRequired<T> = {
[P in keyof T]-?: T[P] extends object ? DeepRequired<T[P]> : T[P]
}
// Usage
type RequiredConfig = DeepRequired<PartialConfig>
// Result: All properties are required at every level
DeepReadonly<T>
Make all properties of a type readonly recursively.
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P]
}
// Usage
type ReadonlyConfig = DeepReadonly<NestedConfig>
// Result: All properties are readonly at every level
const config: ReadonlyConfig = {
app: {
name: 'MyApp',
version: '1.0.0',
features: {
darkMode: true,
analytics: false
}
},
user: {
profile: {
name: 'John',
email: 'john@example.com'
}
}
}
// config.app.name = 'NewApp' // Error: Cannot assign to 'name' because it is a read-only property
Type Extraction Utilities
Extract specific types from complex type structures.
KeysOfType<T, U>
Extract keys of a type that match a specific type.
type KeysOfType<T, U> = {
[K in keyof T]: T[K] extends U ? K : never
}[keyof T]
// Usage
interface UserData {
id: string
name: string
age: number
isActive: boolean
createdAt: Date
tags: string[]
}
type StringKeys = KeysOfType<UserData, string> // 'id' | 'name'
type NumberKeys = KeysOfType<UserData, number> // 'age'
type BooleanKeys = KeysOfType<UserData, boolean> // 'isActive'
type DateKeys = KeysOfType<UserData, Date> // 'createdAt'
type ArrayKeys = KeysOfType<UserData, any[]> // 'tags'
// Example usage
function updateStringField<K extends StringKeys>(
user: UserData,
key: K,
value: string
): UserData {
return { ...user, [key]: value }
}
PickByType<T, U>
Pick properties of a type that match a specific type.
type PickByType<T, U> = Pick<T, KeysOfType<T, U>>
// Usage
type StringFields = PickByType<UserData, string>
// Result: { id: string; name: string }
type NumberFields = PickByType<UserData, number>
// Result: { age: number }
OmitByType<T, U>
Omit properties of a type that match a specific type.
type OmitByType<T, U> = Omit<T, KeysOfType<T, U>>
// Usage
type NonStringFields = OmitByType<UserData, string>
// Result: { age: number; isActive: boolean; createdAt: Date; tags: string[] }
Prettify Type
Clean up complex intersection types for better readability.
Prettify<T>
Flatten intersection types for better TypeScript IntelliSense.
type Prettify<T> = {
[K in keyof T]: T[K]
} & {}
// Usage
type BaseProps = {
id: string
className?: string
}
type ExtendedProps = {
title: string
description?: string
}
type UtilityProps = {
onClick?: () => void
disabled?: boolean
}
// Without Prettify - shows as intersection
type ComplexProps = BaseProps & ExtendedProps & UtilityProps
// With Prettify - shows as single object type
type CleanProps = Prettify<BaseProps & ExtendedProps & UtilityProps>
// Result: {
// id: string
// className?: string
// title: string
// description?: string
// onClick?: () => void
// disabled?: boolean
// }
React Types
Component Types
Comprehensive React component type definitions.
ComponentProps<T>
Extract props from HTML elements or React components.
type ComponentProps<T extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>> =
T extends React.JSXElementConstructor<infer P>
? P
: T extends keyof JSX.IntrinsicElements
? JSX.IntrinsicElements[T]
: never
// Usage
type ButtonProps = ComponentProps<'button'>
// Result: React.ButtonHTMLAttributes<HTMLButtonElement>
type InputProps = ComponentProps<'input'>
// Result: React.InputHTMLAttributes<HTMLInputElement>
// Custom component props
const CustomButton = ({ variant, ...props }: { variant: string } & ButtonProps) => {
return <button {...props} className={`btn btn-${variant}`} />
}
type CustomButtonProps = ComponentProps<typeof CustomButton>
// Result: { variant: string } & React.ButtonHTMLAttributes<HTMLButtonElement>
ComponentRef<T>
Extract ref type from HTML elements or React components.
type ComponentRef<T extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>> =
T extends keyof JSX.IntrinsicElements
? JSX.IntrinsicElements[T] extends React.DetailedHTMLProps<any, infer E>
? E
: never
: T extends React.JSXElementConstructor<any>
? React.ComponentRef<T>
: never
// Usage
type ButtonRef = ComponentRef<'button'> // HTMLButtonElement
type InputRef = ComponentRef<'input'> // HTMLInputElement
type DivRef = ComponentRef<'div'> // HTMLDivElement
// Example usage
const Button = forwardRef<ButtonRef, ButtonProps>((props, ref) => {
return <button ref={ref} {...props} />
})
ForwardRefComponent<T, P>
Type for components created with forwardRef
.
type ForwardRefComponent<
T extends keyof JSX.IntrinsicElements,
P = {}
> = React.ForwardRefExoticComponent<
React.PropsWithoutRef<P & ComponentProps<T>> & React.RefAttributes<ComponentRef<T>>
>
// Usage
interface CustomButtonProps {
variant?: 'primary' | 'secondary'
size?: 'sm' | 'md' | 'lg'
}
const CustomButton: ForwardRefComponent<'button', CustomButtonProps> = forwardRef(
({ variant = 'primary', size = 'md', className, ...props }, ref) => {
return (
<button
ref={ref}
className={cn('btn', `btn-${variant}`, `btn-${size}`, className)}
{...props}
/>
)
}
)
PolymorphicComponent<T, P>
Type for polymorphic components that can render as different elements.
type PolymorphicComponent<
T extends keyof JSX.IntrinsicElements,
P = {}
> = <C extends keyof JSX.IntrinsicElements = T>(
props: {
as?: C
} & P & ComponentProps<C>
) => React.ReactElement | null
// Usage
interface CardProps {
variant?: 'default' | 'elevated'
padding?: '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>
)
}
// Usage examples
<Card>Default div card</Card>
<Card as="section">Section card</Card>
<Card as="article" className="custom-class">Article card</Card>
Common Component Props
Frequently used component prop patterns.
WithChildren
Add children prop to a component.
type WithChildren<T = {}> = T & {
children?: React.ReactNode
}
// Usage
interface CardProps extends WithChildren {
title?: string
variant?: 'default' | 'elevated'
}
function Card({ title, variant = 'default', children }: CardProps) {
return (
<div className={`card card-${variant}`}>
{title && <div className="card-header">{title}</div>}
<div className="card-content">{children}</div>
</div>
)
}
WithClassName
Add className prop to a component.
type WithClassName<T = {}> = T & {
className?: string
}
// Usage
interface ButtonProps extends WithClassName {
variant?: 'primary' | 'secondary'
disabled?: boolean
}
function Button({ variant = 'primary', disabled, className, ...props }: ButtonProps) {
return (
<button
className={cn('btn', `btn-${variant}`, { 'btn-disabled': disabled }, className)}
disabled={disabled}
{...props}
/>
)
}
WithStyle
Add style prop to a component.
type WithStyle<T = {}> = T & {
style?: React.CSSProperties
}
// Usage
interface ContainerProps extends WithChildren, WithClassName, WithStyle {
maxWidth?: string | number
}
function Container({ maxWidth, style, className, children }: ContainerProps) {
return (
<div
className={cn('container', className)}
style={{ maxWidth, ...style }}
>
{children}
</div>
)
}
Event Types
Event Handler Types
Type-safe event handling for React components.
EventHandler<T>
Generic event handler type.
type EventHandler<T = Event> = (event: T) => void
// Usage
interface ButtonProps {
onClick?: EventHandler<MouseEvent>
onKeyDown?: EventHandler<KeyboardEvent>
onFocus?: EventHandler<FocusEvent>
}
function Button({ onClick, onKeyDown, onFocus, ...props }: ButtonProps) {
return (
<button
onClick={onClick}
onKeyDown={onKeyDown}
onFocus={onFocus}
{...props}
/>
)
}
ChangeHandler<T>
Handler for input change events with typed value.
type ChangeHandler<T = string> = (value: T, event: React.ChangeEvent<HTMLInputElement>) => void
// Usage
interface InputProps {
value: string
onChange: ChangeHandler<string>
onNumberChange?: ChangeHandler<number>
}
function Input({ value, onChange, onNumberChange }: InputProps) {
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const newValue = event.target.value
onChange(newValue, event)
if (onNumberChange) {
const numValue = parseFloat(newValue)
if (!isNaN(numValue)) {
onNumberChange(numValue, event)
}
}
}
return <input value={value} onChange={handleChange} />
}
SubmitHandler<T>
Handler for form submission with typed data.
type SubmitHandler<T = unknown> = (data: T, event: React.FormEvent) => void | Promise<void>
// Usage
interface FormData {
name: string
email: string
age: number
}
interface FormProps {
onSubmit: SubmitHandler<FormData>
initialData?: Partial<FormData>
}
function UserForm({ onSubmit, initialData }: FormProps) {
const [formData, setFormData] = useState<FormData>({
name: '',
email: '',
age: 0,
...initialData
})
const handleSubmit = (event: React.FormEvent) => {
event.preventDefault()
onSubmit(formData, event)
}
return (
<form onSubmit={handleSubmit}>
{/* Form fields */}
</form>
)
}
Specific Event Handlers
Pre-defined handlers for common events.
type MouseHandler = EventHandler<React.MouseEvent>
type KeyboardHandler = EventHandler<React.KeyboardEvent>
type FocusHandler = EventHandler<React.FocusEvent>
type TouchHandler = EventHandler<React.TouchEvent>
// Usage
interface InteractiveElementProps {
onMouseEnter?: MouseHandler
onMouseLeave?: MouseHandler
onKeyDown?: KeyboardHandler
onKeyUp?: KeyboardHandler
onFocus?: FocusHandler
onBlur?: FocusHandler
onTouchStart?: TouchHandler
onTouchEnd?: TouchHandler
}
API Types
Request and Response Types
Standardized API communication types.
ApiResponse<T>
Standard API response wrapper.
interface ApiResponse<T = unknown> {
data: T
success: boolean
message?: string
timestamp: string
requestId?: string
}
// Usage
interface User {
id: string
name: string
email: string
}
type UserResponse = ApiResponse<User>
type UsersResponse = ApiResponse<User[]>
async function fetchUser(id: string): Promise<UserResponse> {
const response = await fetch(`/api/users/${id}`)
return response.json()
}
ApiError
Standard API error structure.
interface ApiError {
error: true
code: string
message: string
details?: Record<string, any>
timestamp: string
path?: string
}
// Usage
interface ValidationError extends ApiError {
code: 'VALIDATION_ERROR'
details: {
field: string
rule: string
value: any
}
}
interface NotFoundError extends ApiError {
code: 'NOT_FOUND'
details: {
resource: string
id: string
}
}
// Error handling
async function handleApiCall<T>(apiCall: () => Promise<T>): Promise<T> {
try {
return await apiCall()
} catch (error) {
if (isApiError(error)) {
console.error(`API Error [${error.code}]: ${error.message}`)
throw error
}
throw new Error('Unknown API error')
}
}
function isApiError(error: unknown): error is ApiError {
return typeof error === 'object' && error !== null && 'error' in error
}
PaginatedResponse<T>
Response type for paginated data.
interface PaginationMeta {
page: number
limit: number
total: number
totalPages: number
hasNextPage: boolean
hasPrevPage: boolean
}
interface PaginatedResponse<T = unknown> extends ApiResponse<T[]> {
pagination: PaginationMeta
}
// Usage
type PaginatedUsers = PaginatedResponse<User>
async function fetchUsers(page = 1, limit = 10): Promise<PaginatedUsers> {
const response = await fetch(`/api/users?page=${page}&limit=${limit}`)
return response.json()
}
// Usage in component
function UsersList() {
const [users, setUsers] = useState<PaginatedUsers | null>(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
fetchUsers().then(setUsers).finally(() => setLoading(false))
}, [])
if (loading) return <div>Loading...</div>
if (!users) return <div>No users found</div>
return (
<div>
{users.data.map(user => (
<div key={user.id}>{user.name}</div>
))}
<div>
Page {users.pagination.page} of {users.pagination.totalPages}
</div>
</div>
)
}
ApiEndpoint<TRequest, TResponse>
Type definition for API endpoints.
type ApiEndpoint<TRequest = unknown, TResponse = unknown> = {
request: TRequest
response: TResponse
}
// Usage
interface UserEndpoints {
getUser: ApiEndpoint<{ id: string }, ApiResponse<User>>
getUsers: ApiEndpoint<{ page?: number; limit?: number }, PaginatedResponse<User>>
createUser: ApiEndpoint<CreateUserRequest, ApiResponse<User>>
updateUser: ApiEndpoint<{ id: string } & UpdateUserRequest, ApiResponse<User>>
deleteUser: ApiEndpoint<{ id: string }, { success: boolean }>
}
// Type-safe API client
class UserApiClient {
async getUser(
params: UserEndpoints['getUser']['request']
): Promise<UserEndpoints['getUser']['response']> {
const response = await fetch(`/api/users/${params.id}`)
return response.json()
}
async getUsers(
params: UserEndpoints['getUsers']['request'] = {}
): Promise<UserEndpoints['getUsers']['response']> {
const searchParams = new URLSearchParams()
if (params.page) searchParams.set('page', String(params.page))
if (params.limit) searchParams.set('limit', String(params.limit))
const response = await fetch(`/api/users?${searchParams}`)
return response.json()
}
}
Form Types
Form Data and Validation
Comprehensive form handling types.
FormField<T, V>
Type for individual form fields with validation rules.
interface FormFieldValidation {
required?: boolean
minLength?: number
maxLength?: number
min?: number
max?: number
pattern?: string | RegExp
custom?: (value: any) => boolean | string
}
interface FormField<T = any, V extends FormFieldValidation = {}> {
value: T
validation?: V
error?: string
touched?: boolean
dirty?: boolean
}
// Usage
interface UserFormFields {
name: FormField<string, { required: true; minLength: 2; maxLength: 50 }>
email: FormField<string, { required: true; pattern: 'email' }>
age: FormField<number, { required: true; min: 18; max: 120 }>
bio: FormField<string, { maxLength: 500 }>
}
FormData<T>
Extract form data from form field definitions.
type FormData<T extends Record<string, FormField<any, any>>> = {
[K in keyof T]: T[K] extends FormField<infer U, any> ? U : never
}
// Usage
type UserFormData = FormData<UserFormFields>
// Result: {
// name: string
// email: string
// age: number
// bio: string
// }
ValidationResult<T>
Result of form validation.
interface ValidationResult<T = unknown> {
isValid: boolean
errors: FormErrors<T>
data: T | null
}
type FormErrors<T> = {
[K in keyof T]?: string
}
// Usage
interface UserValidationResult extends ValidationResult<UserFormData> {
isValid: boolean
errors: FormErrors<UserFormData>
data: UserFormData | null
}
function validateUserForm(data: UserFormData): UserValidationResult {
const errors: FormErrors<UserFormData> = {}
if (!data.name || data.name.length < 2) {
errors.name = 'Name must be at least 2 characters'
}
if (!data.email || !isValidEmail(data.email)) {
errors.email = 'Please enter a valid email address'
}
if (!data.age || data.age < 18 || data.age > 120) {
errors.age = 'Age must be between 18 and 120'
}
const isValid = Object.keys(errors).length === 0
return {
isValid,
errors,
data: isValid ? data : null
}
}
FieldValidator<T>
Type for field validation functions.
interface FieldValidationResult {
isValid: boolean
error?: string
}
type FieldValidator<T = any> = (value: T) => FieldValidationResult
// Usage
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 }
}
const ageValidator: FieldValidator<number> = (value) => {
if (value < 18) {
return { isValid: false, error: 'You must be at least 18 years old' }
}
if (value > 120) {
return { isValid: false, error: 'Please enter a valid age' }
}
return { isValid: true }
}
// Compose validators
function composeValidators<T>(...validators: FieldValidator<T>[]): FieldValidator<T> {
return (value: T) => {
for (const validator of validators) {
const result = validator(value)
if (!result.isValid) {
return result
}
}
return { isValid: true }
}
}
const nameValidator = composeValidators<string>(
(value) => value.length >= 2 ? { isValid: true } : { isValid: false, error: 'Too short' },
(value) => value.length <= 50 ? { isValid: true } : { isValid: false, error: 'Too long' }
)
Type Guards and Predicates
Runtime Type Checking
Type guards for runtime type validation.
TypeGuard<T>
Generic type guard function type.
type TypeGuard<T> = (value: unknown) => value is T
// Usage
const isString: TypeGuard<string> = (value): value is string => {
return typeof value === 'string'
}
const isNumber: TypeGuard<number> = (value): value is number => {
return typeof value === 'number' && !isNaN(value)
}
const isObject: TypeGuard<Record<string, unknown>> = (value): value is Record<string, unknown> => {
return typeof value === 'object' && value !== null && !Array.isArray(value)
}
// Complex type guard
const isUser: TypeGuard<User> = (value): value is User => {
return (
isObject(value) &&
isString(value.id) &&
isString(value.name) &&
isString(value.email)
)
}
// Usage
function processUserData(data: unknown) {
if (isUser(data)) {
// TypeScript knows data is User here
console.log(`Processing user: ${data.name}`)
console.log(`Email: ${data.email}`)
} else {
console.error('Invalid user data')
}
}
Predicate<T>
Generic predicate function type.
type Predicate<T> = (value: T) => boolean
// Usage
const isAdult: Predicate<User> = (user) => {
return user.age >= 18
}
const isActiveUser: Predicate<User> = (user) => {
return user.isActive && user.lastLoginAt > new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
}
// Compose predicates
function and<T>(...predicates: Predicate<T>[]): Predicate<T> {
return (value: T) => predicates.every(predicate => predicate(value))
}
function or<T>(...predicates: Predicate<T>[]): Predicate<T> {
return (value: T) => predicates.some(predicate => predicate(value))
}
const isActiveAdult = and(isAdult, isActiveUser)
// Filter users
const activeAdultUsers = users.filter(isActiveAdult)
Advanced Types
Conditional and Mapped Types
Advanced TypeScript type manipulation.
If<C, T, F>
Conditional type helper.
type If<C extends boolean, T, F> = C extends true ? T : F
// Usage
type IsStringArray<T> = T extends string[] ? true : false
type StringArrayResult = If<IsStringArray<string[]>, 'yes', 'no'> // 'yes'
type NumberArrayResult = If<IsStringArray<number[]>, 'yes', 'no'> // 'no'
DeepKeyOf<T>
Get all possible deep keys of an object type.
type DeepKeyOf<T> = T extends object
? {
[K in keyof T]: K extends string
? T[K] extends object
? K | `${K}.${DeepKeyOf<T[K]>}`
: K
: never
}[keyof T]
: never
// Usage
interface NestedObject {
user: {
profile: {
name: string
settings: {
theme: string
notifications: boolean
}
}
}
app: {
version: string
}
}
type DeepKeys = DeepKeyOf<NestedObject>
// Result: "user" | "app" | "user.profile" | "user.profile.name" |
// "user.profile.settings" | "user.profile.settings.theme" |
// "user.profile.settings.notifications" | "app.version"
PathValue<T, P>
Get the type of a value at a specific path.
type PathValue<T, P extends string> = P extends keyof T
? T[P]
: P extends `${infer K}.${infer R}`
? K extends keyof T
? PathValue<T[K], R>
: never
: never
// Usage
type UserName = PathValue<NestedObject, 'user.profile.name'> // string
type Theme = PathValue<NestedObject, 'user.profile.settings.theme'> // string
type Notifications = PathValue<NestedObject, 'user.profile.settings.notifications'> // boolean
Next Steps
- Learn about custom type patterns for advanced usage
- Review integration guide for framework-specific usage
- Check out best practices for optimal type usage