🎯 IntelliSense Support
Get autocomplete suggestions for all methods, parameters, and response properties in your IDE.
The iRacing Data Client SDK is built with TypeScript first, providing complete type safety and excellent developer experience. This guide shows you how to leverage TypeScript features effectively.
🎯 IntelliSense Support
Get autocomplete suggestions for all methods, parameters, and response properties in your IDE.
🛡️ Compile-Time Checking
Catch errors before runtime with TypeScript’s static type checking.
📚 Self-Documenting Code
Types serve as inline documentation, making code more readable and maintainable.
The SDK automatically infers all types - no manual type annotations needed:
// TypeScript knows all the types automaticallyconst iracing = new IRacingDataClient({ /* ... */ });
// 'info' is typed as MemberInfoResponseconst info = await iracing.member.info();
// TypeScript knows these properties existconsole.log(info.custId); // ✅ Validconsole.log(info.displayName); // ✅ Validconsole.log(info.wrongProp); // ❌ TypeScript errorImport specific types when needed:
import { IRacingDataClient, type MemberInfoResponse, type CarGetResponse, type License} from 'iracing-data-client';
// Use types for function parametersfunction processLicense(license: License) { console.log(`Class: ${license.licenseLevel}`); console.log(`SR: ${license.safetyRating / 100}`);}
// Use types for variableslet memberData: MemberInfoResponse | null = null;memberData = await iracing.member.info();TypeScript provides full type safety for nested properties:
const info = await iracing.member.info();
// TypeScript knows the structureconsole.log(info.displayName);console.log(info.licenses.oval.irating);console.log(info.licenses.sportsCar.safetyRating);
// Optional-style handling still works where fields may be nullableif (info.account.countryRules) { console.log('Country-specific rules are configured');}// Type narrowing with conditional checksconst results = await iracing.results.get({ subsessionId: 12345 });
if (results.sessionResults.length > 0) { const session = results.sessionResults[0];
// TypeScript knows session is defined here session.results.forEach(result => { if (result.reasonOut === 'Running') { // Type narrowed to running cars console.log(`P${result.finishPosition}: ${result.displayName}`); } });}The SDK enforces required parameters at compile time:
// ❌ TypeScript error - missing required parameterawait iracing.member.get();
// ✅ Valid - required parameter providedawait iracing.member.get({ custIds: [123456]});
// Optional parametersawait iracing.results.searchSeries({ seasonId: 3456, // Required raceWeekNum: 5, // Optional official: true // Optional});All parameters are validated using Zod schemas:
// The SDK validates types at runtime tootry { await iracing.member.get({ custIds: 'not-an-array' // ❌ TypeScript error });} catch (error) { // Zod validation error if types are bypassed}Some endpoints support additional semantic preflight checks beyond shape validation.
const iracing = new IRacingDataClient({ auth: { type: 'password-limited', clientId: process.env.IRACING_CLIENT_ID!, clientSecret: process.env.IRACING_CLIENT_SECRET!, username: process.env.IRACING_USERNAME!, password: process.env.IRACING_PASSWORD!, }, validateParams: true, // Keep Zod schema checks enabled validateSemanticParams: false, // Disable extra metadata-based preflight checks});Use this when you want strict type/schema validation but do not want additional API metadata requests.
Create reusable typed helpers:
// Generic retry function with type preservationasync function retryWithBackoff<T>( fn: () => Promise<T>, retries = 3): Promise<T> { try { return await fn(); } catch (error) { if (retries > 0) { await new Promise(r => setTimeout(r, 1000)); return retryWithBackoff(fn, retries - 1); } throw error; }}
// Type is preserved through the helperconst data = await retryWithBackoff( () => iracing.member.info());// 'data' is typed as MemberInfoResponseCreate custom type guards:
import { IRacingError } from 'iracing-data-client';
// Type predicate functionfunction isRateLimitError(error: unknown): error is IRacingError { return error instanceof IRacingError && error.isRateLimited;}
try { const data = await iracing.member.info();} catch (error) { if (isRateLimitError(error)) { // TypeScript knows error is IRacingError here console.log(`Rate limited with status: ${error.status}`); }}Work with different response types:
type RaceResult = | { status: 'finished'; position: number; time: string } | { status: 'dnf'; reason: string; lapsCompleted: number } | { status: 'dq'; reason: string };
function processResult(result: RaceResult) { switch (result.status) { case 'finished': // TypeScript knows 'position' exists here console.log(`Finished P${result.position}`); break; case 'dnf': // TypeScript knows 'lapsCompleted' exists here console.log(`DNF after ${result.lapsCompleted} laps`); break; case 'dq': console.log(`DQ: ${result.reason}`); break; }}Extract nested types from responses:
import type { MemberGetResponse } from 'iracing-data-client';
// Extract the member type from the responsetype Member = MemberGetResponse['members'][0];
// Extract license typetype License = Member['licenses'][0];
// Use extracted typesfunction formatLicense(license: License): string { return `${license.categoryName} - Class ${license.licenseLevel}`;}Use TypeScript utilities for flexible types:
import type { MemberGetParams } from 'iracing-data-client';
// Make all properties optionaltype PartialParams = Partial<MemberGetParams>;
// Make all properties requiredtype StrictParams = Required<MemberGetParams>;
// Pick specific propertiestype IdOnly = Pick<MemberGetParams, 'custIds'>;
// Omit propertiestype NoLicenses = Omit<MemberGetParams, 'includeLicenses'>;Optimize VS Code for TypeScript development:
{ "typescript.preferences.includePackageJsonAutoImports": "on", "typescript.updateImportsOnFileMove.enabled": "always", "typescript.suggest.autoImports": true, "typescript.inlayHints.parameterNames.enabled": "all", "typescript.inlayHints.propertyDeclarationTypes.enabled": true}Recommended tsconfig.json settings:
{ "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "lib": ["ES2022"], "strict": true, "strictNullChecks": true, "noImplicitAny": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "declaration": true, "declarationMap": true, "sourceMap": true, "outDir": "./dist", "rootDir": "./src" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"]}Create a type-safe query builder:
class MemberQueryBuilder { private params: Partial<MemberGetParams> = {};
withIds(...ids: number[]): this { this.params.custIds = ids; return this; }
includeLicenses(): this { this.params.includeLicenses = true; return this; }
async execute(): Promise<MemberGetResponse> { if (!this.params.custIds) { throw new Error('Customer IDs required'); }
return iracing.member.get(this.params as MemberGetParams); }}
// Usage with chainingconst members = await new MemberQueryBuilder() .withIds(123456, 789012) .includeLicenses() .execute();Create type-safe data repositories:
class MemberRepository { constructor(private iracing: IRacingDataClient) {}
async findById(id: number): Promise<Member | null> { const response = await this.iracing.member.get({ custIds: [id] });
return response.members[0] || null; }
async findByIds(ids: number[]): Promise<Member[]> { const response = await this.iracing.member.get({ custIds: ids });
return response.members; }
async getCurrentMember(): Promise<MemberInfo> { return this.iracing.member.info(); }}Problem: Types not recognized in IDE
Solution:
# Restart TypeScript server in VS CodeCmd/Ctrl + Shift + P -> "TypeScript: Restart TS Server"
# Or reinstall typesnpm install --save-dev @types/nodeProblem: Conflicting type definitions
Solution:
{ "compilerOptions": { "skipLibCheck": true, "types": ["node"] }}Problem: Cannot import types
Solution:
// Use type-only imports for typesimport type { MemberInfoResponse } from 'iracing-data-client';
// Import both runtime and typesimport { IRacingDataClient, type IRacingError } from 'iracing-data-client';