Core API
defineCommand
Type-safe command definitions with full TypeScript inference
defineCommand#
defineCommand is a helper that gives you fully inferred TypeScript types in your handler based on the param schema you declare โ with zero runtime overhead (identity function).
import { createSurf, defineCommand } from '@surfjs/core'ย // params are automatically typed from the schemaconst search = defineCommand({ description: 'Search products', params: { query: { type: 'string', required: true, description: 'Search term' }, limit: { type: 'number', description: 'Max results' }, }, run(params) { // params.query โ string (required โ never undefined) // params.limit โ number | undefined (optional) return db.products.search(params.query, { limit: params.limit }) },})ย const surf = await createSurf({ name: 'My Store', commands: { search },})๐ก Tip: Without
defineCommand, handlers receiveRecord<string, unknown>. With it, required params arestring/number/booleanand optional params include| undefinedโ all inferred automatically.
Use defineCommand when you want type-safe handlers without writing manual interfaces. It's especially useful for large APIs with many commands.
InferParam and InferParams
Lower-level utility types for extracting the TypeScript type of a single param or a full params object from a ParamSchema. Useful when building abstractions on top of Surf.
import type { InferParam, InferParams } from '@surfjs/core'import type { ParamSchema } from '@surfjs/core'ย // Infer the type of a single param definitiontype QueryType = InferParam<{ type: 'string'; required: true }>// => stringย type LimitType = InferParam<{ type: 'number' }>// => number (InferParam maps to the base type โ optionality is handled by InferParams)ย // Infer the full params object from a ParamSchema mapconst myParams = { query: { type: 'string', required: true }, limit: { type: 'number' },} satisfies Record<string, ParamSchema>ย type MyParams = InferParams<typeof myParams>// => { query: string; limit?: number }// Required keys are non-optional; all others get `?` (optional)Key distinction: InferParam maps a single schema to its base TypeScript type (string, number, boolean, etc.). It does not add | undefined โ that's handled by InferParams, which splits required vs optional keys and applies ? to optional ones. Use InferParam for individual type extraction and InferParams for full param objects.
defineCommand uses these types internally. Import them directly when you need to type-check param schemas in utility functions, generic wrappers, or custom command builders.