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