Validator
See source codeTable of contents
The main validator class that implements the Validatable interface. This is the base class for all validators and provides methods for validation, type checking, and composing validators.
class Validator<T> implements Validatable<T> {}
Example
const numberValidator = new Validator((value) => {
if (typeof value !== 'number') {
throw new ValidationError('Expected number')
}
return value
})
const result = numberValidator.validate(42) // Returns 42 as number
Constructor
Creates a new Validator instance.
validationFn - Function that validates and returns a value of type T validateUsingKnownGoodVersionFn - Optional performance-optimized validation function
Parameters
Name | Description |
---|---|
|
|
|
|
Properties
validateUsingKnownGoodVersionFn
readonly validateUsingKnownGoodVersionFn?:
| undefined
| ValidatorUsingKnownGoodVersionFn<T>
validationFn
readonly validationFn: ValidatorFn<T>
Methods
check( )
Adds an additional validation check without changing the resulting value type. Can be called with just a check function, or with a name for better error messages.
check(name: string, checkFn: (value: T) => void): Validator<T>
Example
import { T, ValidationError } from '@tldraw/validate'
// Basic check without name
const evenNumber = T.number.check((value) => {
if (value % 2 !== 0) {
throw new ValidationError('Expected even number')
}
})
// Named checks for better error messages in complex validators
const shapePositionValidator = T.object({
x: T.number.check('finite', (value) => {
if (!Number.isFinite(value)) {
throw new ValidationError('Position must be finite')
}
}),
y: T.number.check('within-bounds', (value) => {
if (value < -10000 || value > 10000) {
throw new ValidationError(
'Position must be within bounds (-10000 to 10000)'
)
}
}),
})
// Error will be: "At x (check finite): Position must be finite"
Parameters
Name | Description |
---|---|
|
Name for the check (used in error messages) |
|
Function that validates the value (should throw on invalid input) |
Returns
Validator<T>
A new validator with the additional check
isValid( )
Type guard that checks if a value is valid without throwing an error.
isValid(value: unknown): value is T
Example
import { T } from '@tldraw/validate'
function processUserInput(input: unknown) {
if (T.string.isValid(input)) {
// input is now typed as string within this block
return input.toUpperCase()
}
if (T.number.isValid(input)) {
// input is now typed as number within this block
return input.toFixed(2)
}
throw new Error('Expected string or number')
}
Parameters
Name | Description |
---|---|
|
The value to check |
Returns
value is T
True if the value is valid, false otherwise
nullable( )
Returns a new validator that also accepts null values.
nullable(): Validator<null | T>
Example
import { T } from '@tldraw/validate'
const assetValidator = T.object({
id: T.string,
name: T.string,
src: T.srcUrl.nullable(), // Can be null if not loaded yet
mimeType: T.string.nullable(),
})
const asset = assetValidator.validate({
id: 'image-123',
name: 'photo.jpg',
src: null, // Valid - asset not loaded yet
mimeType: 'image/jpeg',
})
optional( )
Returns a new validator that also accepts undefined values.
optional(): Validator<T | undefined>
Example
import { T } from '@tldraw/validate'
const shapeConfigValidator = T.object({
type: T.literal('rectangle'),
x: T.number,
y: T.number,
label: T.string.optional(), // Optional property
metadata: T.object({ created: T.string }).optional(),
})
// Both of these are valid:
const shape1 = shapeConfigValidator.validate({ type: 'rectangle', x: 0, y: 0 })
const shape2 = shapeConfigValidator.validate({
type: 'rectangle',
x: 0,
y: 0,
label: 'My Shape',
})
refine( )
Creates a new validator by refining this validator with additional logic that can transform the validated value to a new type.
refine<U>(otherValidationFn: (value: T) => U): Validator<U>
Example
import { T, ValidationError } from '@tldraw/validate'
// Transform string to ensure it starts with a prefix
const prefixedIdValidator = T.string.refine((id) => {
return id.startsWith('shape:') ? id : `shape:${id}`
})
const id1 = prefixedIdValidator.validate('rectangle-123') // Returns "shape:rectangle-123"
const id2 = prefixedIdValidator.validate('shape:circle-456') // Returns "shape:circle-456"
// Parse and validate JSON strings
const jsonValidator = T.string.refine((str) => {
try {
return JSON.parse(str)
} catch {
throw new ValidationError('Invalid JSON string')
}
})
Parameters
Name | Description |
---|---|
|
Function that transforms/validates the value to type U |
Returns
Validator<U>
A new validator that validates to type U
validate( )
Validates an unknown value and returns it with the correct type. The returned value is guaranteed to be referentially equal to the passed value.
validate(value: unknown): T
Example
import { T } from '@tldraw/validate'
const name = T.string.validate('Alice') // Returns "Alice" as string
const title = T.string.validate('') // Returns "" (empty strings are valid)
// These will throw ValidationError:
T.string.validate(123) // Expected string, got a number
T.string.validate(null) // Expected string, got null
T.string.validate(undefined) // Expected string, got undefined
Parameters
Name | Description |
---|---|
|
The unknown value to validate |
Returns
T
The validated value with type T
validateUsingKnownGoodVersion( )
Performance-optimized validation using a previously validated value. If the new value is referentially equal to the known good value, returns the known good value immediately.
validateUsingKnownGoodVersion(knownGoodValue: T, newValue: unknown): T
Example
import { T } from '@tldraw/validate'
const userValidator = T.object({
name: T.string,
settings: T.object({ theme: T.literalEnum('light', 'dark') }),
})
const user = userValidator.validate({
name: 'Alice',
settings: { theme: 'light' },
})
// Later, with partially changed data:
const newData = { name: 'Alice', settings: { theme: 'dark' } }
const updated = userValidator.validateUsingKnownGoodVersion(user, newData)
// Only validates the changed 'theme' field for better performance
Parameters
Name | Description |
---|---|
|
A previously validated value |
|
The new value to validate |
Returns
T
The validated value, potentially reusing the known good value