import { IndexKey } from '@tldraw/utils'; import { JsonValue } from '@tldraw/utils'; import { MakeUndefinedOptional } from '@tldraw/utils'; /** * Validator that accepts any value and types it as 'any'. This should generally be avoided * as it bypasses type safety, but can be used as an escape hatch for prototyping. * * @example * ```ts * const result = T.any.validate(anything) // Returns the value as any * // result is typed as any - use with caution! * ``` * @public */ declare const any: Validator; /** * Validator that ensures a value is an array. Does not validate the contents of the array. * Use T.arrayOf() to validate both the array structure and its contents. * * @example * ```ts * const items = T.array.validate([1, "hello", true]) // Returns unknown[] * T.array.validate("not array") // Throws ValidationError: "Expected an array, got a string" * * // For typed arrays, use T.arrayOf: * const numbers = T.arrayOf(T.number).validate([1, 2, 3]) // Returns number[] * ``` * @public */ declare const array: Validator; /** * Creates a validator for arrays where each element is validated using the provided validator. * * @param itemValidator - Validator to use for each array element * @returns An ArrayOfValidator that validates both array structure and element types * @throws ValidationError When the value is not an array or when any element is invalid * @example * ```ts * const numberArray = T.arrayOf(T.number) * numberArray.validate([1, 2, 3]) // Returns number[] * numberArray.validate([1, "2", 3]) // Throws ValidationError at index 1 * * const userArray = T.arrayOf(T.object({ name: T.string, age: T.number })) * ``` * @public */ declare function arrayOf(itemValidator: Validatable): ArrayOfValidator; /** * Validator for arrays where each element is validated using the provided item validator. * Extends the base Validator class with array-specific validation methods. * * @example * ```ts * const stringArray = new ArrayOfValidator(T.string) * const numbers = stringArray.validate(["a", "b", "c"]) // Returns string[] * * const userArray = T.arrayOf(T.object({ name: T.string, age: T.number })) * ``` * @public */ export declare class ArrayOfValidator extends Validator { readonly itemValidator: Validatable; /** * Creates a new ArrayOfValidator. * * itemValidator - Validator used to validate each array element */ constructor(itemValidator: Validatable); /** * Returns a new validator that ensures the array is not empty. * * @returns A new validator that rejects empty arrays * @throws ValidationError When the array is empty * @example * ```ts * const nonEmptyStrings = T.arrayOf(T.string).nonEmpty() * nonEmptyStrings.validate(["hello"]) // Valid * nonEmptyStrings.validate([]) // Throws ValidationError * ``` */ nonEmpty(): Validator; /** * Returns a new validator that ensures the array has more than one element. * * @returns A new validator that requires at least 2 elements * @throws ValidationError When the array has 1 or fewer elements * @example * ```ts * const multipleItems = T.arrayOf(T.string).lengthGreaterThan1() * multipleItems.validate(["a", "b"]) // Valid * multipleItems.validate(["a"]) // Throws ValidationError * ``` */ lengthGreaterThan1(): Validator; } /** * Validator that ensures a value is a bigint. * * @example * ```ts * const largeNumber = T.bigint.validate(123n) // Returns 123n * T.bigint.validate(123) // Throws ValidationError: "Expected bigint, got a number" * ``` * @public */ declare const bigint: Validator; /** * Validator that ensures a value is a boolean. * * @example * ```ts * const isActive = T.boolean.validate(true) // Returns true * const isEnabled = T.boolean.validate(false) // Returns false * T.boolean.validate("true") // Throws ValidationError: "Expected boolean, got a string" * ``` * @public */ declare const boolean: Validator; /** * Creates a validator for dictionary objects where both keys and values are validated. * Useful for validating objects used as key-value maps. * * @param keyValidator - Validator for object keys * @param valueValidator - Validator for object values * @returns A DictValidator that validates all keys and values * @throws ValidationError When any key or value is invalid * @example * ```ts * const scores = T.dict(T.string, T.number) * scores.validate({ "alice": 100, "bob": 85 }) // Valid * * const userPrefs = T.dict(T.string, T.object({ * theme: T.literalEnum('light', 'dark'), * notifications: T.boolean * })) * ``` * @public */ declare function dict(keyValidator: Validatable, valueValidator: Validatable): DictValidator; /** * Validator for dictionary/map objects where both keys and values are validated. * Useful for validating objects used as key-value stores. * * @example * ```ts * const scoreDict = new DictValidator(T.string, T.number) * const scores = scoreDict.validate({ * "alice": 100, * "bob": 85, * "charlie": 92 * }) * // scores is typed as Record * ``` * @public */ export declare class DictValidator extends Validator> { readonly keyValidator: Validatable; readonly valueValidator: Validatable; /** * Creates a new DictValidator. * * keyValidator - Validator for object keys * valueValidator - Validator for object values */ constructor(keyValidator: Validatable, valueValidator: Validatable); } /** * Validator for HTTP and HTTPS URLs only. Rejects all other protocols. * * @example * ```ts * const apiUrl = T.httpUrl.validate("https://api.example.com") // Valid * const httpUrl = T.httpUrl.validate("http://localhost:3000") // Valid * T.httpUrl.validate("") // Valid (empty string allowed) * T.httpUrl.validate("ftp://files.example.com") // Throws ValidationError (not http/https) * ``` * @public */ declare const httpUrl: Validator; /** * Validator for IndexKey values used in tldraw's indexing system. An IndexKey is a string * that meets specific format requirements for use as a database index. * * @throws ValidationError When the string is not a valid IndexKey format * @example * ```ts * const key = T.indexKey.validate("valid_index_key") // Returns IndexKey * T.indexKey.validate("invalid key!") // Throws ValidationError (invalid format) * ``` * @public */ declare const indexKey: Validator; /** * Validator that ensures a value is an integer (whole number). * * @example * ```ts * const count = T.integer.validate(42) // Returns 42 * T.integer.validate(3.14) // Throws ValidationError: "Expected an integer, got 3.14" * T.integer.validate(-5) // Returns -5 (negative integers are valid) * ``` * @public */ declare const integer: Validator; /** * Creates a validator for JSON dictionaries (objects with string keys and JSON-serializable values). * * @returns A DictValidator that validates string keys and JSON values * @throws ValidationError When keys are not strings or values are not JSON-serializable * @example * ```ts * const config = T.jsonDict().validate({ * "setting1": "value", * "setting2": 42, * "setting3": ["a", "b", "c"], * "setting4": { nested: true } * }) * ``` * @public */ declare function jsonDict(): DictValidator; /** * Validator that ensures a value is valid JSON (string, number, boolean, null, array, or plain object). * Rejects functions, undefined, symbols, and other non-JSON values. * * @example * ```ts * const data = T.jsonValue.validate({ name: "Alice", scores: [1, 2, 3], active: true }) * T.jsonValue.validate(undefined) // Throws ValidationError * T.jsonValue.validate(() => {}) // Throws ValidationError * ``` * @public */ declare const jsonValue: Validator; /** * Validator for URLs that are safe to use as user-facing links. Accepts http, https, and mailto protocols. * This validator provides security by rejecting potentially dangerous protocols like javascript:. * * @example * ```ts * const link = T.linkUrl.validate("https://example.com") // Valid * const email = T.linkUrl.validate("mailto:user@example.com") // Valid * T.linkUrl.validate("") // Valid (empty string allowed) * T.linkUrl.validate("javascript:alert(1)") // Throws ValidationError (unsafe protocol) * ``` * @public */ declare const linkUrl: Validator; /** * Creates a validator that only accepts a specific literal value. * * @param expectedValue - The exact value that must be matched * @returns A validator that only accepts the specified literal value * @throws ValidationError When the value doesn't match the expected literal * @example * ```ts * const trueValidator = T.literal(true) * trueValidator.validate(true) // Returns true * trueValidator.validate(false) // Throws ValidationError * * const statusValidator = T.literal("active") * statusValidator.validate("active") // Returns "active" * statusValidator.validate("inactive") // Throws ValidationError * ``` * @public */ declare function literal(expectedValue: T): Validator; /** * Creates a validator that only accepts one of the provided literal values. * This is a convenience function that creates a setEnum from the provided values. * * @param values - The allowed literal values * @returns A validator that only accepts the provided literal values * @throws ValidationError When the value is not one of the allowed literals * @example * ```ts * const themeValidator = T.literalEnum('light', 'dark', 'auto') * themeValidator.validate('light') // Returns 'light' * themeValidator.validate('blue') // Throws ValidationError: Expected "light" or "dark" or "auto", got blue * ``` * @public */ declare function literalEnum(...values: Values): Validator; /** * Creates a validator for named model objects with enhanced error reporting. The model name * will be included in error messages to provide better debugging context. * * @param name - The name of the model (used in error messages) * @param validator - The validator for the model structure * @returns A Validator with enhanced error reporting that includes the model name * @throws ValidationError With model name context when validation fails * @example * ```ts * const userModel = T.model('User', T.object({ * id: T.string, * name: T.string, * email: T.linkUrl * })) * * // Error message will be: "At User.email: Expected a valid url, got 'invalid-email'" * ``` * @public */ declare function model(name: string, validator: Validatable): Validator; /** * Validator that ensures a value is a finite, non-zero number. Allows negative numbers. * Useful for scale factors that can be negative (for flipping) but not zero. * * @example * ```ts * const scale = T.nonZeroFiniteNumber.validate(-1.5) // Returns -1.5 (valid, allows negative) * T.nonZeroFiniteNumber.validate(0) // Throws ValidationError: "Expected a non-zero number, got 0" * T.nonZeroFiniteNumber.validate(Infinity) // Throws ValidationError * ``` * @public */ declare const nonZeroFiniteNumber: Validator; /** * Validator that ensures a value is a positive integer (\> 0). Rejects zero and negative integers. * * @example * ```ts * const itemCount = T.nonZeroInteger.validate(1) // Returns 1 * T.nonZeroInteger.validate(0) // Throws ValidationError: "Expected a non-zero positive integer, got 0" * T.nonZeroInteger.validate(-5) // Throws ValidationError: "Expected a non-zero positive integer, got -5" * ``` * @public */ declare const nonZeroInteger: Validator; /** * Validator that ensures a value is a positive number (\> 0). Rejects zero and negative numbers. * * @example * ```ts * const quantity = T.nonZeroNumber.validate(0.01) // Returns 0.01 * T.nonZeroNumber.validate(0) // Throws ValidationError: "Expected a non-zero positive number, got 0" * T.nonZeroNumber.validate(-5) // Throws ValidationError: "Expected a non-zero positive number, got -5" * ``` * @public */ declare const nonZeroNumber: Validator; /** * Creates a validator that accepts either the validated type or null. * * @param validator - The base validator to make nullable * @returns A validator that accepts T or null * @example * ```ts * const nullableString = T.nullable(T.string) * nullableString.validate("hello") // Returns "hello" * nullableString.validate(null) // Returns null * nullableString.validate(undefined) // Throws ValidationError * ``` * @public */ declare function nullable(validator: Validatable): Validator; /** * Validator that ensures a value is a finite, non-NaN number. Rejects Infinity, -Infinity, and NaN. * * @example * ```ts * const count = T.number.validate(42) // Returns 42 as number * T.number.validate(NaN) // Throws ValidationError: "Expected a number, got NaN" * T.number.validate(Infinity) // Throws ValidationError: "Expected a finite number, got Infinity" * ``` * @public */ declare const number: Validator; /* Excluded from this release type: numberUnion */ /** * Creates a validator for objects with a defined shape. Each property is validated using * its corresponding validator from the config object. * * @param config - Object mapping property names to their validators * @returns An ObjectValidator that validates the object structure and all properties * @throws ValidationError When the value is not an object or when any property is invalid * @example * ```ts * const userValidator = T.object({ * name: T.string, * age: T.number, * email: T.string.optional(), * isActive: T.boolean * }) * * const user = userValidator.validate({ * name: "Alice", * age: 25, * email: "alice@example.com", * isActive: true * }) * // user is typed with full type safety * ``` * @public */ declare function object(config: { readonly [K in keyof Shape]: Validatable; }): ObjectValidator>; /** * Validator for objects with a defined shape. Each property is validated using its corresponding * validator from the config object. Can be configured to allow or reject unknown properties. * * @example * ```ts * const userValidator = new ObjectValidator({ * name: T.string, * age: T.number, * email: T.string.optional() * }) * * const user = userValidator.validate({ * name: "Alice", * age: 25, * email: "alice@example.com" * }) * ``` * @public */ export declare class ObjectValidator extends Validator { readonly config: { readonly [K in keyof Shape]: Validatable; }; private readonly shouldAllowUnknownProperties; /** * Creates a new ObjectValidator. * * config - Object mapping property names to their validators * shouldAllowUnknownProperties - Whether to allow properties not defined in config */ constructor(config: { readonly [K in keyof Shape]: Validatable; }, shouldAllowUnknownProperties?: boolean); /** * Returns a new validator that allows unknown properties in the validated object. * * @returns A new ObjectValidator that accepts extra properties * @example * ```ts * const flexibleUser = T.object({ name: T.string }).allowUnknownProperties() * flexibleUser.validate({ name: "Alice", extra: "allowed" }) // Valid * ``` */ allowUnknownProperties(): ObjectValidator; /** * Creates a new ObjectValidator by extending this validator with additional properties. * * @param extension - Object mapping new property names to their validators * @returns A new ObjectValidator that validates both original and extended properties * @example * ```ts * const baseUser = T.object({ name: T.string, age: T.number }) * const adminUser = baseUser.extend({ * permissions: T.arrayOf(T.string), * isAdmin: T.boolean * }) * // adminUser validates: { name: string; age: number; permissions: string[]; isAdmin: boolean } * ``` */ extend>(extension: { readonly [K in keyof Extension]: Validatable; }): ObjectValidator; } /** * Creates a validator that accepts either the validated type or undefined. * * @param validator - The base validator to make optional * @returns A validator that accepts T or undefined * @example * ```ts * const optionalString = T.optional(T.string) * optionalString.validate("hello") // Returns "hello" * optionalString.validate(undefined) // Returns undefined * optionalString.validate(null) // Throws ValidationError * ``` * @public */ declare function optional(validator: Validatable): Validator; /** * Creates a validator that accepts values matching either of two validators. * Tries the first validator, and if it fails, tries the second validator. * * @param v1 - The first validator to try * @param v2 - The second validator to try if the first fails * @returns A validator that accepts values matching either validator * @throws ValidationError When the value matches neither validator (throws error from v2) * @example * ```ts * const stringOrNumber = T.or(T.string, T.number) * stringOrNumber.validate("hello") // Returns "hello" as string * stringOrNumber.validate(42) // Returns 42 as number * stringOrNumber.validate(true) // Throws ValidationError from number validator * ``` * @public */ declare function or(v1: Validatable, v2: Validatable): Validator; /** * Validator that ensures a value is a non-negative integer (\>= 0). * Despite the name "positive", this validator accepts zero. * * @example * ```ts * const index = T.positiveInteger.validate(5) // Returns 5 * const start = T.positiveInteger.validate(0) // Returns 0 (valid) * T.positiveInteger.validate(-1) // Throws ValidationError: "Expected a positive integer, got -1" * T.positiveInteger.validate(3.14) // Throws ValidationError: "Expected an integer, got 3.14" * ``` * @public */ declare const positiveInteger: Validator; /** * Validator that ensures a value is a non-negative number (\>= 0). * Despite the name "positive", this validator accepts zero. * * @example * ```ts * const price = T.positiveNumber.validate(29.99) // Returns 29.99 * const free = T.positiveNumber.validate(0) // Returns 0 (valid) * T.positiveNumber.validate(-1) // Throws ValidationError: "Expected a positive number, got -1" * ``` * @public */ declare const positiveNumber: Validator; /** * Creates a validator that only accepts values from a given Set of allowed values. * * @param values - Set containing the allowed values * @returns A validator that only accepts values from the provided set * @throws ValidationError When the value is not in the allowed set * @example * ```ts * const allowedColors = new Set(['red', 'green', 'blue'] as const) * const colorValidator = T.setEnum(allowedColors) * colorValidator.validate('red') // Returns 'red' * colorValidator.validate('yellow') // Throws ValidationError * ``` * @public */ declare function setEnum(values: ReadonlySet): Validator; /** * Validator for URLs that are safe to use as asset sources. Accepts http, https, data, and asset protocols. * The asset: protocol refers to tldraw's local IndexedDB object store. * * @example * ```ts * const imageUrl = T.srcUrl.validate("https://example.com/image.png") // Valid * const dataUrl = T.srcUrl.validate("data:image/png;base64,iVBORw0...") // Valid * const assetUrl = T.srcUrl.validate("asset:abc123") // Valid (local asset reference) * T.srcUrl.validate("") // Valid (empty string allowed) * ``` * @public */ declare const srcUrl: Validator; /** * Validator that ensures a value is a string. * * @example * ```ts * const name = T.string.validate("hello") // Returns "hello" as string * T.string.validate(123) // Throws ValidationError: "Expected string, got a number" * ``` * @public */ declare const string: Validator; declare namespace T { export { literal, arrayOf, object, jsonDict, dict, union, model, setEnum, optional, nullable, literalEnum, or, ValidatorFn, ValidatorUsingKnownGoodVersionFn, Validatable, ValidationError, TypeOf, Validator, ArrayOfValidator, ObjectValidator, UnionValidatorConfig, UnionValidator, DictValidator, unknown, any, string, number, positiveNumber, nonZeroNumber, nonZeroFiniteNumber, unitInterval, integer, positiveInteger, nonZeroInteger, boolean, bigint, array, unknownObject, jsonValue, linkUrl, srcUrl, httpUrl, indexKey } } export { T } /** * Utility type that extracts the validated type from a Validatable object. * Useful for deriving TypeScript types from validator definitions. * * @example * ```ts * const userValidator = T.object({ name: T.string, age: T.number }) * type User = TypeOf // { name: string; age: number } * ``` * @public */ declare type TypeOf> = V extends Validatable ? T : never; /** * Creates a validator for discriminated union types. Validates objects that can be one of * several variants, distinguished by a discriminator property. * * @param key - The discriminator property name used to determine the variant * @param config - Object mapping variant names to their validators * @returns A UnionValidator that validates based on the discriminator value * @throws ValidationError When the discriminator is invalid or the variant validation fails * @example * ```ts * const shapeValidator = T.union('type', { * circle: T.object({ type: T.literal('circle'), radius: T.number }), * square: T.object({ type: T.literal('square'), size: T.number }), * triangle: T.object({ type: T.literal('triangle'), base: T.number, height: T.number }) * }) * * const circle = shapeValidator.validate({ type: 'circle', radius: 5 }) * // circle is typed as { type: 'circle'; radius: number } * ``` * @public */ declare function union>(key: Key, config: Config): UnionValidator; /** * Validator for discriminated union types. Validates objects that can be one of several variants, * distinguished by a discriminator property (key) that indicates which variant the object represents. * * @example * ```ts * const shapeValidator = new UnionValidator('type', { * circle: T.object({ type: T.literal('circle'), radius: T.number }), * square: T.object({ type: T.literal('square'), size: T.number }) * }, () => { throw new Error('Unknown shape') }, false) * * const circle = shapeValidator.validate({ type: 'circle', radius: 5 }) * // circle is typed as { type: 'circle'; radius: number } * ``` * @public */ export declare class UnionValidator, UnknownValue = never> extends Validator | UnknownValue> { private readonly key; private readonly config; private readonly unknownValueValidation; private readonly useNumberKeys; /** * Creates a new UnionValidator. * * key - The discriminator property name used to determine the variant * config - Object mapping variant names to their validators * unknownValueValidation - Function to handle unknown variants * useNumberKeys - Whether the discriminator uses number keys instead of strings */ constructor(key: Key, config: Config, unknownValueValidation: (value: object, variant: string) => UnknownValue, useNumberKeys: boolean); private expectObject; private getMatchingSchemaAndVariant; /** * Returns a new UnionValidator that can handle unknown variants using the provided function. * * @param unknownValueValidation - Function to validate/transform unknown variants * @returns A new UnionValidator that accepts unknown variants * @example * ```ts * const shapeValidator = T.union('type', { circle: circleValidator }) * .validateUnknownVariants((obj, variant) => { * console.warn(`Unknown shape type: ${variant}`) * return obj as UnknownShape * }) * ``` */ validateUnknownVariants(unknownValueValidation: (value: object, variant: string) => Unknown): UnionValidator; } /** * Configuration type for union validators. Each variant must be a validator that produces * an object with the discriminator key set to the variant name. * * @example * ```ts * type ShapeConfig = UnionValidatorConfig<'type', { * circle: Validatable<{ type: 'circle'; radius: number }> * square: Validatable<{ type: 'square'; size: number }> * }> * ``` * @public */ export declare type UnionValidatorConfig = { readonly [Variant in keyof Config]: Validatable & { validate(input: any): { readonly [K in Key]: Variant; }; }; }; /** * Validator that ensures a value is a number in the unit interval [0, 1]. * Useful for opacity, percentages expressed as decimals, and other normalized values. * * @example * ```ts * const opacity = T.unitInterval.validate(0.5) // Returns 0.5 * T.unitInterval.validate(0) // Returns 0 (valid) * T.unitInterval.validate(1) // Returns 1 (valid) * T.unitInterval.validate(1.5) // Throws ValidationError * T.unitInterval.validate(-0.1) // Throws ValidationError * ``` * @public */ declare const unitInterval: Validator; /** * Validator that accepts any value without type checking. Useful as a starting point for * building custom validations or when you need to accept truly unknown data. * * @example * ```ts * const result = T.unknown.validate(anything) // Returns the value as-is * // result is typed as unknown * ``` * @public */ declare const unknown: Validator; /** * Validator that ensures a value is an object (non-null, non-array). Does not validate * the properties of the object. * * @example * ```ts * const obj = T.unknownObject.validate({ any: "properties" }) // Returns Record * T.unknownObject.validate(null) // Throws ValidationError: "Expected object, got null" * T.unknownObject.validate([1, 2, 3]) // Throws ValidationError: "Expected object, got an array" * ``` * @public */ declare const unknownObject: Validator>; /** * Interface for objects that can validate unknown values and return typed results. * This is the core interface implemented by all validators in the validation system. * * @example * ```ts * const customValidator: Validatable = { * validate(value) { * if (typeof value !== 'number') { * throw new ValidationError('Expected number') * } * return value * } * } * ``` * @public */ declare interface Validatable { /** * Validates an unknown value and returns it with the correct type. * * @param value - The unknown value to validate * @returns The validated value with type T * @throws ValidationError When validation fails */ validate(value: unknown): T; /** * Performance-optimized validation that can use a previously validated value * to avoid revalidating unchanged parts of the data structure. * * If the value has not changed but is not referentially equal, the function * should return the previous value. * * @param knownGoodValue - A previously validated value * @param newValue - The new value to validate * @returns The validated value, potentially reusing the known good value for performance * @throws ValidationError When validation fails */ validateUsingKnownGoodVersion?(knownGoodValue: T, newValue: unknown): T; } /** * Error thrown when validation fails. Provides detailed information about what went wrong * and where in the data structure the error occurred. * * @example * ```ts * try { * validator.validate(invalidData) * } catch (error) { * if (error instanceof ValidationError) { * console.log(error.message) // "At users.0.email: Expected valid URL" * console.log(error.path) // ['users', 0, 'email'] * console.log(error.rawMessage) // "Expected valid URL" * } * } * ``` * @public */ declare class ValidationError extends Error { readonly rawMessage: string; readonly path: ReadonlyArray; name: string; /** * Creates a new ValidationError with contextual information about where the error occurred. * * rawMessage - The raw error message without path information * path - Array indicating the location in the data structure where validation failed */ constructor(rawMessage: string, path?: ReadonlyArray); } /** * 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. * * @example * ```ts * 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 * ``` * @public */ export declare class Validator implements Validatable { readonly validationFn: ValidatorFn; readonly validateUsingKnownGoodVersionFn?: undefined | ValidatorUsingKnownGoodVersionFn; /* Excluded from this release type: skipSameValueCheck */ /** * Creates a new Validator instance. * * validationFn - Function that validates and returns a value of type T * validateUsingKnownGoodVersionFn - Optional performance-optimized validation function * skipSameValueCheck - Internal flag to skip dev check for validators that transform values */ constructor(validationFn: ValidatorFn, validateUsingKnownGoodVersionFn?: undefined | ValidatorUsingKnownGoodVersionFn, /** @internal */ skipSameValueCheck?: boolean); /** * Validates an unknown value and returns it with the correct type. The returned value is * guaranteed to be referentially equal to the passed value. * * @param value - The unknown value to validate * @returns The validated value with type T * @throws ValidationError When validation fails * @example * ```ts * 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 * ``` */ validate(value: unknown): T; /** * 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. * * @param knownGoodValue - A previously validated value * @param newValue - The new value to validate * @returns The validated value, potentially reusing the known good value * @throws ValidationError When validation fails * @example * ```ts * 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 * ``` */ validateUsingKnownGoodVersion(knownGoodValue: T, newValue: unknown): T; /** * Type guard that checks if a value is valid without throwing an error. * * @param value - The value to check * @returns True if the value is valid, false otherwise * @example * ```ts * 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') * } * ``` */ isValid(value: unknown): value is T; /** * Returns a new validator that also accepts null values. * * @returns A new validator that accepts T or null * @example * ```ts * 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" * }) * ``` */ nullable(): Validator; /** * Returns a new validator that also accepts undefined values. * * @returns A new validator that accepts T or undefined * @example * ```ts * 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" * }) * ``` */ optional(): Validator; /** * Creates a new validator by refining this validator with additional logic that can transform * the validated value to a new type. * * @param otherValidationFn - Function that transforms/validates the value to type U * @returns A new validator that validates to type U * @throws ValidationError When validation or refinement fails * @example * ```ts * 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') * } * }) * ``` */ refine(otherValidationFn: (value: T) => U): Validator; /** * 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. * * @param name - Name for the check (used in error messages) * @param checkFn - Function that validates the value (should throw on invalid input) * @returns A new validator with the additional check * @throws ValidationError When the check fails * @example * ```ts * 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" * ``` */ check(name: string, checkFn: (value: T) => void): Validator; /** * Adds an additional validation check without changing the resulting value type. * * @param checkFn - Function that validates the value (should throw on invalid input) * @returns A new validator with the additional check * @throws ValidationError When the check fails */ check(checkFn: (value: T) => void): Validator; } /** * A function that validates and returns a value of type T from unknown input. * The function should throw a ValidationError if the value is invalid. * * @param value - The unknown value to validate * @returns The validated value of type T * @throws \{ValidationError\} When the value doesn't match the expected type * @example * ```ts * const stringValidator: ValidatorFn = (value) => { * if (typeof value !== 'string') { * throw new ValidationError('Expected string') * } * return value * } * ``` * @public */ declare type ValidatorFn = (value: unknown) => T; /** * A performance-optimized validation function that can use a previously validated value * to avoid revalidating unchanged parts of the data structure. * * @param knownGoodValue - A previously validated value of type In * @param value - The unknown value to validate * @returns The validated value of type Out * @throws ValidationError When the value doesn't match the expected type * @example * ```ts * const optimizedValidator: ValidatorUsingKnownGoodVersionFn = ( * knownGood, * newValue * ) => { * if (Object.is(knownGood, newValue)) return knownGood * return fullValidation(newValue) * } * ``` * @public */ declare type ValidatorUsingKnownGoodVersionFn = (knownGoodValue: In, value: unknown) => Out; export { }