Advanced
TypeScript Support
DBindly v2.3.0 includes TypeScript definitions for full type safety and IDE support.
Installation
The type definitions are included with the main package. Reference them in your project:
<script src="https://api.dbindly.com/dbindly.min.js"></script>
<script src="https://api.dbindly.com/dbindly.d.ts"></script>
Or download dbindly.d.ts for local use.
Type Definitions
DBindlyConfig
Configuration options for initialization:
interface DBindlyConfig {
apiUrl: string;
apiKey?: string;
cache?: boolean;
cacheTTL?: number;
debug?: boolean;
retryAttempts?: number;
retryDelay?: number;
timeout?: number;
showSkeletons?: boolean;
onError?: (error: Error) => void;
onLoad?: (data: Record<string, unknown>) => void;
onDataLoaded?: (data: Record<string, unknown>) => void;
}
DBindlyMetrics
Performance metrics returned by getMetrics():
interface DBindlyMetrics {
requestCount: number;
totalLoadTime: number;
cacheHits: number;
cacheMisses: number;
errors: number;
averageLoadTime: number; // Calculated
cacheHitRate: number; // Calculated
}
CollectionOptions
Options for collection queries:
interface CollectionSort {
field: string;
direction: 'asc' | 'desc';
}
interface CollectionFilter {
field: string;
operator: 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'contains' | 'startsWith' | 'endsWith';
value: unknown;
}
interface CollectionOptions {
page?: number;
limit?: number;
fields?: string[];
sort?: CollectionSort;
filters?: CollectionFilter[];
search?: string;
}
CollectionResponse
Response from collection operations:
interface CollectionResponse<T = Record<string, unknown>> {
data: T[];
total: number;
page: number;
limit: number;
totalPages: number;
hasMore: boolean;
}
Event Types
Custom event detail types:
interface ModelChangeEventDetail {
field: string;
value: unknown;
element: HTMLElement;
}
interface ActionEventDetail {
action: string;
data: Record<string, unknown>;
element: HTMLElement;
}
interface ErrorEventDetail {
error: Error;
field?: string;
}
Typed Usage Examples
Basic Initialization
// TypeScript knows all valid config options
DBindly.init({
apiUrl: 'https://api.example.com',
apiKey: 'pk_live_xxx',
cache: true,
cacheTTL: 300000,
onError: (error: Error) => {
console.error('DBindly error:', error.message);
}
});
Loading Data
// Returns Promise<Record<string, unknown>>
const data = await DBindly.load('product-123');
// Type assertion for specific data shape
interface Product {
id: string;
name: string;
price: number;
category: string;
}
const product = await DBindly.load('product-123') as Product;
console.log(product.name); // TypeScript knows this exists
Typed Collections
interface BlogPost {
id: string;
title: string;
excerpt: string;
author: {
name: string;
avatar: string;
};
publishedAt: string;
tags: string[];
}
// Generic type parameter for response data
const result = await DBindly.fetchCollection<BlogPost>('blog-posts', {
page: 1,
limit: 10,
sort: { field: 'publishedAt', direction: 'desc' }
});
// result.data is typed as BlogPost[]
result.data.forEach(post => {
console.log(post.title); // TypeScript knows this exists
console.log(post.author.name); // Nested properties too
});
Event Listeners
// Typed event listener for model changes
document.addEventListener('dbindly:model-change', (e: CustomEvent<ModelChangeEventDetail>) => {
console.log('Field:', e.detail.field);
console.log('Value:', e.detail.value);
console.log('Element:', e.detail.element);
});
// Typed action handler
document.addEventListener('dbindly:action', (e: CustomEvent<ActionEventDetail>) => {
const { action, data, element } = e.detail;
switch (action) {
case 'submit-form':
handleFormSubmit(data);
break;
case 'delete-item':
handleDelete(element.dataset.id);
break;
}
});
// Typed error handler
document.addEventListener('dbindly:error', (e: CustomEvent<ErrorEventDetail>) => {
const { error, field } = e.detail;
if (field) {
showFieldError(field, error.message);
} else {
showGlobalError(error.message);
}
});
Form Data
interface ContactForm {
name: string;
email: string;
message: string;
subscribe: boolean;
}
// Type assertion for form data
const formData = DBindly.getFormData() as ContactForm;
// Now TypeScript knows the shape
console.log(formData.name);
console.log(formData.email);
Metrics
const metrics: DBindlyMetrics = DBindly.getMetrics();
console.log(`Requests: ${metrics.requestCount}`);
console.log(`Cache hit rate: ${(metrics.cacheHitRate * 100).toFixed(1)}%`);
console.log(`Average load time: ${metrics.averageLoadTime}ms`);
Global Declaration
DBindly is available globally:
// Access via window
window.DBindly.init({ apiUrl: '...' });
// Or directly (ambient declaration)
DBindly.init({ apiUrl: '...' });
The type definitions include global augmentation:
declare global {
interface Window {
DBindly: DBindly;
}
const DBindly: DBindly;
interface DocumentEventMap {
'dbindly:model-change': CustomEvent<ModelChangeEventDetail>;
'dbindly:action': CustomEvent<ActionEventDetail>;
'dbindly:error': CustomEvent<ErrorEventDetail>;
'dbindly:loaded': CustomEvent<{ data: Record<string, unknown> }>;
'dbindly:collection-loaded': CustomEvent<{ slug: string; data: CollectionResponse }>;
}
}
Complete TypeScript Example
// types.ts
interface User {
id: string;
email: string;
profile: {
firstName: string;
lastName: string;
avatar?: string;
};
preferences: {
newsletter: boolean;
theme: 'light' | 'dark';
};
}
// app.ts
import type { DBindlyConfig, DBindlyMetrics, CollectionResponse } from './dbindly';
const config: DBindlyConfig = {
apiUrl: process.env.API_URL || 'https://api.example.com',
apiKey: process.env.DBINDLY_KEY,
cache: true,
cacheTTL: 5 * 60 * 1000, // 5 minutes
debug: process.env.NODE_ENV === 'development',
onError: (error: Error) => {
DBindly.showError(error.message);
trackError(error);
},
onDataLoaded: (data: Record<string, unknown>) => {
trackPageLoad(data);
}
};
DBindly.init(config);
// Load user profile with type safety
async function loadUserProfile(userId: string): Promise<User | null> {
try {
const user = await DBindly.load(`user-${userId}`) as User;
return user;
} catch (error) {
console.error('Failed to load user:', error);
return null;
}
}
// Handle form submission with typed data
document.addEventListener('dbindly:action', async (e: CustomEvent<ActionEventDetail>) => {
if (e.detail.action === 'update-profile') {
const formData = e.detail.data as Partial<User['profile']>;
DBindly.clearErrors();
if (!formData.firstName?.trim()) {
DBindly.showError('First name is required', 'profile.firstName');
return;
}
try {
await updateProfile(formData);
DBindly.setData({ profile: formData });
} catch (error) {
DBindly.showError('Failed to update profile');
}
}
});
// Monitor performance
function logMetrics(): void {
const metrics: DBindlyMetrics = DBindly.getMetrics();
console.table({
'Total Requests': metrics.requestCount,
'Cache Hits': metrics.cacheHits,
'Cache Misses': metrics.cacheMisses,
'Hit Rate': `${(metrics.cacheHitRate * 100).toFixed(1)}%`,
'Avg Load Time': `${metrics.averageLoadTime.toFixed(0)}ms`,
'Errors': metrics.errors
});
}
// Initialize app
async function init(): Promise<void> {
const user = await loadUserProfile('current');
if (user) {
console.log(`Welcome, ${user.profile.firstName}!`);
}
// Log metrics in development
if (process.env.NODE_ENV === 'development') {
setInterval(logMetrics, 30000);
}
}
init();
Next Steps
- JavaScript API - Complete API reference
- Configuration - All config options
- Advanced Templating - Template syntax