Documentation Index Fetch the complete documentation index at: https://docs.grainql.com/llms.txt
Use this file to discover all available pages before exploring further.
Type-Safe by Default
Grain SDK is written in TypeScript and includes complete type definitions:
import { createGrainAnalytics , GrainAnalytics } from '@grainql/analytics-web' ;
const grain : GrainAnalytics = createGrainAnalytics ({
tenantId: 'your-tenant-id'
});
No @types packages needed - types are built-in.
Configuration Types
Full type safety for configuration:
import { GrainConfig } from '@grainql/analytics-web' ;
const config : GrainConfig = {
tenantId: 'your-tenant-id' ,
authStrategy: 'JWT' , // 'NONE' | 'SERVER_SIDE' | 'JWT'
batchSize: 50 ,
debug: true
};
const grain = createGrainAnalytics ( config );
TypeScript catches invalid options at compile time.
Event Types
Type your event properties:
interface ButtonClickEvent {
button_name : string ;
page : string ;
timestamp : number ;
}
grain . track ( 'button_clicked' , {
button_name: 'signup' ,
page: '/home' ,
timestamp: Date . now ()
} as ButtonClickEvent );
Or create typed track functions:
function trackButtonClick ( button : string , page : string ) {
grain . track ( 'button_clicked' , {
button_name: button ,
page ,
timestamp: Date . now ()
});
}
Template Event Types
Template methods have built-in types:
import { LoginEventProperties } from '@grainql/analytics-web' ;
const loginEvent : LoginEventProperties = {
method: 'email' ,
success: true ,
rememberMe: false
};
await grain . trackLogin ( loginEvent );
// TypeScript knows all valid properties
Custom Event Types
Create type-safe custom events:
type CustomEventName =
| 'video_started'
| 'video_paused'
| 'video_completed' ;
interface VideoEventProps {
video_id : string ;
duration : number ;
progress : number ;
}
function trackVideoEvent (
name : CustomEventName ,
props : VideoEventProps
) {
grain . track ( name , props );
}
// Type-safe usage
trackVideoEvent ( 'video_started' , {
video_id: 'abc123' ,
duration: 120 ,
progress: 0
});
React Hook Types
Hooks have full type inference:
import { useConfig } from '@grainql/analytics-web/react' ;
function Component () {
// TypeScript infers return type
const { value , isRefreshing , error , refresh } = useConfig ( 'hero_text' );
// value: string | undefined
// isRefreshing: boolean
// error: Error | null
// refresh: () => Promise<void>
}
Generic Client Type
For dependency injection or testing:
import { GrainAnalytics } from '@grainql/analytics-web' ;
class AnalyticsService {
constructor ( private grain : GrainAnalytics ) {}
trackPageView ( page : string ) {
this . grain . track ( 'page_viewed' , { page });
}
}
const service = new AnalyticsService ( grain );
Strict Null Checks
SDK works with strict null checks:
// tsconfig.json
{
"compilerOptions" : {
"strict" : true ,
"strictNullChecks" : true
}
}
const userId = grain . getUserId ();
// userId: string | null
if ( userId ) {
console . log ( userId . toUpperCase ()); // Safe
}
Auth Provider Types
Type-safe auth providers:
import { AuthProvider } from '@grainql/analytics-web' ;
const authProvider : AuthProvider = {
async getToken () : Promise < string > {
const token = await auth0 . getAccessToken ();
return token ;
}
};
const grain = createGrainAnalytics ({
tenantId: 'your-tenant-id' ,
authStrategy: 'JWT' ,
authProvider
});
Remote Config Types
Type your configurations:
interface AppConfig {
hero_text : string ;
button_color : string ;
feature_enabled : 'true' | 'false' ;
}
// Type-safe config access
function getTypedConfig < K extends keyof AppConfig >(
key : K
) : AppConfig [ K ] | undefined {
return grain . getConfig ( key ) as AppConfig [ K ] | undefined ;
}
const heroText = getTypedConfig ( 'hero_text' ); // string | undefined
const color = getTypedConfig ( 'button_color' ); // string | undefined
Enum Event Names
Use enums for event names:
enum EventName {
PAGE_VIEWED = 'page_viewed' ,
BUTTON_CLICKED = 'button_clicked' ,
FORM_SUBMITTED = 'form_submitted'
}
grain . track ( EventName . PAGE_VIEWED , { page: '/home' });
grain . track ( EventName . BUTTON_CLICKED , { button: 'signup' });
Autocomplete suggests valid event names.
Type Guards
Create type guards for safer code:
function isConfigLoaded ( value : string | undefined ) : value is string {
return value !== undefined && value . length > 0 ;
}
const config = grain . getConfig ( 'feature_flag' );
if ( isConfigLoaded ( config )) {
// TypeScript knows config is string here
console . log ( config . toUpperCase ());
}
Exporting Types
Re-export types for your app:
// types/analytics.ts
export type {
GrainAnalytics ,
GrainConfig ,
GrainEvent ,
AuthProvider ,
LoginEventProperties ,
CheckoutEventProperties
} from '@grainql/analytics-web' ;
export type {
UseConfigResult ,
UseAllConfigsResult
} from '@grainql/analytics-web/react' ;
// components/MyComponent.tsx
import type { UseConfigResult } from '@/types/analytics' ;
Testing with Types
Type-safe testing:
import { GrainAnalytics } from '@grainql/analytics-web' ;
const mockGrain : jest . Mocked < GrainAnalytics > = {
track: jest . fn (),
setUserId: jest . fn (),
getConfig: jest . fn (),
// ... other methods
} as any ;
// Type-safe mock usage
mockGrain . track ( 'test_event' , { foo: 'bar' });
expect ( mockGrain . track ). toHaveBeenCalledWith (
'test_event' ,
{ foo: 'bar' }
);
Type-Safe Wrappers
Create type-safe wrappers for your domain:
class TypedGrainAnalytics {
constructor ( private grain : GrainAnalytics ) {}
trackSignup ( method : 'email' | 'google' | 'github' ) {
this . grain . track ( 'signup' , { method });
}
trackPurchase ( amount : number , currency : 'USD' | 'EUR' | 'GBP' ) {
this . grain . track ( 'purchase' , { amount , currency });
}
}
const analytics = new TypedGrainAnalytics ( grain );
analytics . trackSignup ( 'email' ); // Type-safe
// analytics.trackSignup('facebook'); // Error: invalid method
Best Practices
1. Use Type Imports : Import only types when possible:
import type { GrainConfig } from '@grainql/analytics-web' ;
2. Define Event Interfaces : Type your event properties
3. Leverage Inference : Let TypeScript infer return types
4. Use Enums : For event names and categories
5. Strict Mode : Enable strict TypeScript checks
Next Steps
API Reference See all available types
React Hooks Type-safe React integration