ResourcefulNumberType
The ResourcefulNumberType class provides comprehensive floating-point number validation and schema generation for numeric fields. It supports range constraints, precision formats, and multiple validation based on OpenAPI 3.0 specifications.
For complete API reference, see ResourcefulNumberType.
Overview
ResourcefulNumberType is designed for floating-point numeric values, supporting:
- Range Validation: Configurable minimum and maximum value constraints
- Precision Control: Support for float (32-bit) and double (64-bit) precision
- Exclusive Bounds: Support for exclusive minimum and maximum values
- Multiple Validation: Ensure values are multiples of a specified number
- Type Safety: Full TypeScript support with validated configuration options
Basic Usage
Simple Number Validation
import { ResourcefulNumberType } from '@nhtio/lucid-resourceful/definitions'
// Basic number with range constraints
const percentageType = ResourcefulNumberType({
minimum: 0.0,
maximum: 100.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'float',
multipleOf: 0.01
})
// Price with precision
const priceType = ResourcefulNumberType({
minimum: 0.01,
maximum: 999999.99,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01
})With Decorators
import { resourcefulColumn } from '@nhtio/lucid-resourceful'
class Product extends compose(BaseModel, withResourceful({ name: 'Product' })) {
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: 0.01,
maximum: 999999.99,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01
}),
nullable: false
})
declare price: number
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: 0.0,
maximum: 5.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'float',
multipleOf: 0.1
}),
nullable: true
})
declare rating: number
}Configuration Options
Required Options
minimum
- Type:
number - Required: Yes
The minimum allowed value for the number.
const positiveType = ResourcefulNumberType({
minimum: 0.0,
maximum: 1000.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 1.0
})exclusiveMinimum
- Type:
boolean - Required: Yes
Whether the minimum value is exclusive (value must be greater than minimum).
// Value must be > 0 (exclusive)
const exclusiveType = ResourcefulNumberType({
minimum: 0.0,
maximum: 100.0,
exclusiveMinimum: true, // Value must be > 0
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01
})
// Value can be >= 0 (inclusive)
const inclusiveType = ResourcefulNumberType({
minimum: 0.0,
maximum: 100.0,
exclusiveMinimum: false, // Value can be >= 0
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01
})maximum
- Type:
number - Required: Yes
The maximum allowed value for the number.
const boundedType = ResourcefulNumberType({
minimum: -1000.0,
maximum: 1000.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 1.0
})exclusiveMaximum
- Type:
boolean - Required: Yes
Whether the maximum value is exclusive (value must be less than maximum).
// Value must be < 100 (exclusive)
const exclusiveMaxType = ResourcefulNumberType({
minimum: 0.0,
maximum: 100.0,
exclusiveMinimum: false,
exclusiveMaximum: true, // Value must be < 100
format: 'double',
multipleOf: 0.01
})format
- Type:
'float' | 'double' - Required: Yes
Precision format for the number following OpenAPI specifications.
'float': 32-bit floating point (single precision)'double': 64-bit floating point (double precision)
// Single precision for performance
const floatType = ResourcefulNumberType({
minimum: 0.0,
maximum: 100.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'float',
multipleOf: 0.1
})
// Double precision for accuracy
const doubleType = ResourcefulNumberType({
minimum: 0.0,
maximum: 100.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01
})multipleOf
- Type:
number - Required: Yes
The value must be a multiple of this number.
// Values must be multiples of 0.25 (0.25, 0.5, 0.75, 1.0, etc.)
const quarterType = ResourcefulNumberType({
minimum: 0.0,
maximum: 10.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.25
})
// Whole numbers only
const wholeType = ResourcefulNumberType({
minimum: 0.0,
maximum: 100.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 1.0
})Common Modifiers
All base interface modifiers are supported:
// Read-only number (like calculated values)
const readOnlyType = ResourcefulNumberType({
minimum: 0.0,
maximum: 1000000.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01,
readOnly: true
})
// Nullable number
const optionalType = ResourcefulNumberType({
minimum: 0.0,
maximum: 100.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'float',
multipleOf: 0.1,
nullable: true
})Common Patterns
Currency Values
const currencyType = ResourcefulNumberType({
minimum: 0.01,
maximum: 999999.99,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01
})
@resourcefulColumn.number({
type: currencyType,
nullable: false
})
declare price: number
@resourcefulColumn.number({
type: currencyType,
nullable: true
})
declare discount: numberPercentage Values
const percentageType = ResourcefulNumberType({
minimum: 0.0,
maximum: 100.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'float',
multipleOf: 0.01
})
@resourcefulColumn.number({
type: percentageType,
nullable: false
})
declare taxRate: number
@resourcefulColumn.number({
type: percentageType,
nullable: true
})
declare completionPercentage: numberRating Systems
// 5-star rating system
const starRatingType = ResourcefulNumberType({
minimum: 1.0,
maximum: 5.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'float',
multipleOf: 0.5 // Allow half-star ratings
})
// 10-point scale
const scaleRatingType = ResourcefulNumberType({
minimum: 1.0,
maximum: 10.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'float',
multipleOf: 0.1
})
@resourcefulColumn.number({
type: starRatingType,
nullable: true
})
declare rating: numberGeographic Coordinates
// Latitude: -90 to +90 degrees
const latitudeType = ResourcefulNumberType({
minimum: -90.0,
maximum: 90.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.000001 // Precision to ~0.1 meters
})
// Longitude: -180 to +180 degrees
const longitudeType = ResourcefulNumberType({
minimum: -180.0,
maximum: 180.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.000001
})
class Location extends compose(BaseModel, withResourceful({ name: 'Location' })) {
@resourcefulColumn.number({
type: latitudeType,
nullable: false
})
declare latitude: number
@resourcefulColumn.number({
type: longitudeType,
nullable: false
})
declare longitude: number
}Weight and Measurement
// Weight in kilograms
const weightType = ResourcefulNumberType({
minimum: 0.01,
maximum: 10000.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01
})
// Temperature in Celsius
const temperatureType = ResourcefulNumberType({
minimum: -273.15, // Absolute zero
maximum: 1000.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.1
})
@resourcefulColumn.number({
type: weightType,
nullable: true
})
declare weight: number
@resourcefulColumn.number({
type: temperatureType,
nullable: true
})
declare temperature: numberAdvanced Examples
Financial Calculations
class Financial extends compose(BaseModel, withResourceful({ name: 'Financial' })) {
// Interest rate as percentage (0.01% to 100%)
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: 0.01,
maximum: 100.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01
}),
nullable: false
})
declare interestRate: number
// Principal amount
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: 1.0,
maximum: 10000000.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01
}),
nullable: false
})
declare principal: number
// Return on investment (can be negative)
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: -100.0, // -100% (total loss)
maximum: 1000.0, // 1000% gain
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01
}),
nullable: true
})
declare roi: number
}Scientific Measurements
class Measurement extends compose(BaseModel, withResourceful({ name: 'Measurement' })) {
// pH level (0.0 to 14.0)
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: 0.0,
maximum: 14.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'float',
multipleOf: 0.01
}),
nullable: true
})
declare phLevel: number
// Pressure in pascals
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: 0.0,
maximum: 1000000000.0, // 1 GPa
exclusiveMinimum: true, // Pressure must be > 0
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.1
}),
nullable: true
})
declare pressure: number
// Humidity percentage
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: 0.0,
maximum: 100.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'float',
multipleOf: 0.1
}),
nullable: true
})
declare humidity: number
}Performance Metrics
class Performance extends compose(BaseModel, withResourceful({ name: 'Performance' })) {
// Response time in milliseconds
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: 0.1,
maximum: 60000.0, // 1 minute max
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.1
}),
nullable: false
})
declare responseTime: number
// CPU usage percentage
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: 0.0,
maximum: 100.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'float',
multipleOf: 0.01
}),
nullable: true
})
declare cpuUsage: number
// Throughput (requests per second)
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: 0.0,
maximum: 100000.0,
exclusiveMinimum: true, // Must be > 0
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01
}),
nullable: true
})
declare throughput: number
}Statistical Data
class Statistics extends compose(BaseModel, withResourceful({ name: 'Statistics' })) {
// Standard deviation (always positive)
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: 0.0,
maximum: 1000000.0,
exclusiveMinimum: true, // Standard deviation > 0
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.000001
}),
nullable: true
})
declare standardDeviation: number
// Correlation coefficient (-1 to +1)
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: -1.0,
maximum: 1.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.001
}),
nullable: true
})
declare correlation: number
// P-value (0 to 1)
@resourcefulColumn.number({
type: ResourcefulNumberType({
minimum: 0.0,
maximum: 1.0,
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.00001
}),
nullable: true
})
declare pValue: number
}Exclusive vs Inclusive Bounds
Understanding the difference between exclusive and inclusive bounds:
// Inclusive bounds: value can equal the boundary
const inclusiveType = ResourcefulNumberType({
minimum: 0.0, // Value can be exactly 0.0
maximum: 100.0, // Value can be exactly 100.0
exclusiveMinimum: false,
exclusiveMaximum: false,
format: 'double',
multipleOf: 0.01
})
// Exclusive bounds: value cannot equal the boundary
const exclusiveType = ResourcefulNumberType({
minimum: 0.0, // Value must be > 0.0
maximum: 100.0, // Value must be < 100.0
exclusiveMinimum: true,
exclusiveMaximum: true,
format: 'double',
multipleOf: 0.01
})
// Mixed bounds: common for rates and percentages
const mixedType = ResourcefulNumberType({
minimum: 0.0, // Value can be exactly 0.0
maximum: 100.0, // Value must be < 100.0
exclusiveMinimum: false,
exclusiveMaximum: true,
format: 'double',
multipleOf: 0.01
})OpenAPI Schema Generation
ResourcefulNumberType generates comprehensive OpenAPI 3.0 schemas:
const numberType = ResourcefulNumberType({
minimum: 0.0,
maximum: 100.0,
exclusiveMinimum: false,
exclusiveMaximum: true,
format: 'double',
multipleOf: 0.01
})
// Generated OpenAPI schema:
{
"type": "number",
"minimum": 0.0,
"maximum": 100.0,
"exclusiveMaximum": true,
"format": "double",
"multipleOf": 0.01
}Best Practices
- Choose appropriate precision: Use
floatfor performance,doublefor accuracy - Set realistic bounds: Define practical minimum and maximum values
- Use appropriate multipleOf: Match precision to your business requirements
- Consider exclusive bounds: Use when boundary values are invalid
- Validate currency carefully: Use appropriate precision for monetary values
- Handle negative values: Consider whether negative values make sense
- Document units: Make units clear (meters, dollars, percentage, etc.)
- Test edge cases: Verify behavior at boundaries and with extreme values
- Consider overflow: Be aware of JavaScript number limitations
- Use consistent precision: Maintain consistent decimal places across related fields
Format Guidelines
Float vs Double
Use
'float'for:- Performance-critical applications
- Values where precision beyond 7 decimal places isn't needed
- Simple percentages and ratings
- Display coordinates with moderate precision
Use
'double'for:- Financial calculations requiring precision
- Scientific measurements
- Geographic coordinates requiring high precision
- Statistical calculations
MultipleOf Guidelines
// Currency (cents precision)
multipleOf: 0.01
// Percentages (hundredths)
multipleOf: 0.01
// High precision coordinates
multipleOf: 0.000001
// Ratings (half-point precision)
multipleOf: 0.5
// Whole numbers only
multipleOf: 1.0