Skip to content

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 ​

typescript
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 ​

typescript
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.

typescript
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).

typescript
// 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.

typescript
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).

typescript
// 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)
typescript
// 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.

typescript
// 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:

typescript
// 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 ​

typescript
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: number

Percentage Values ​

typescript
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: number

Rating Systems ​

typescript
// 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: number

Geographic Coordinates ​

typescript
// 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 ​

typescript
// 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: number

Advanced Examples ​

Financial Calculations ​

typescript
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 ​

typescript
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 ​

typescript
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 ​

typescript
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:

typescript
// 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:

typescript
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 ​

  1. Choose appropriate precision: Use float for performance, double for accuracy
  2. Set realistic bounds: Define practical minimum and maximum values
  3. Use appropriate multipleOf: Match precision to your business requirements
  4. Consider exclusive bounds: Use when boundary values are invalid
  5. Validate currency carefully: Use appropriate precision for monetary values
  6. Handle negative values: Consider whether negative values make sense
  7. Document units: Make units clear (meters, dollars, percentage, etc.)
  8. Test edge cases: Verify behavior at boundaries and with extreme values
  9. Consider overflow: Be aware of JavaScript number limitations
  10. 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 ​

typescript
// 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