Skip to content

Commit

Permalink
Updates documentation, comments and naming
Browse files Browse the repository at this point in the history
  • Loading branch information
didley committed Aug 2, 2023
1 parent c89ea10 commit 43cb1f4
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 24 deletions.
71 changes: 71 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,72 @@
# decimal-input

A utils to assist with handling decimal input fields.

## Installing

```shell
# NPM
npm install @didley/decimal-input
# Yarn
yarn add @didley/decimal-input
```

## `decimalInput`

`decimalInput` parses & validates a decimal string returning a valid decimal string & number else invalid. Generally you'll want to make your input have a controlled value and only update it and your stored float when `decimalInput`s return value is `true`.

### `decimalInput` example

```ts
function handleChange(event) {
const decimal = decimalInput(event.target.value);

if (decimal.valid) {
setInputValue(decimal.value);
setFloatValue(decimal.float);
}
}
```

### `decimalInput` function definition

```ts
function decimalInput<T extends SafeIntOrFloat | number = SafeIntOrFloat>(
/** Your inputs value */
value: string,
options?: {
/** Minimum input number to be valid */
min?: number;
/** Maximum input number to be valid */
max?: number;
/** Number of decimal input to be valid */
decimalPlaces?: number;
}
):
| {
float: T;
value: string;
valid: true;
}
| {
float: undefined;
value: undefined;
valid: false;
};
```

## `DecimalUtil.validateFloat`

`validateFloat` is the same float validation used within `decimalInput`. Useful when requiring the same validation outside of `decimalInput`.

## `DecimalUtil.isSafeIntOrFloat`

`isSafeIntOrFloat` is a type guard to determine if a value is of type `SafeIntOrFloat`

## `SafeIntOrFloat` type

A branded type to allow strong typing of a decimal(float) value.

You can use `isSafeIntOrFloat` to determine if a value or assert with `as SafeIntOrFloat` if you're sure.

see [Branded types explication](https://egghead.io/blog/using-branded-types-in-typescript)
35 changes: 30 additions & 5 deletions dist/decimalInput.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
/** @see https://egghead.io/blog/using-branded-types-in-typescript */
/**
* A branded type to allow strong typing of a decimal(float) value.
*
* You can use `isSafeIntOrFloat` to determine if a value or assert with `as SafeIntOrFloat` if you're sure.
*
* @see {@link https://egghead.io/blog/using-branded-types-in-typescript | Branded types explication}
*/
type SafeIntOrFloat = number & {
__type: 'SafeIntOrFloat';
};
type ReturnType<Float extends SafeIntOrFloat | number> = {
float: Float;
type DecimalInputReturnType<F extends SafeIntOrFloat | number> = {
float: F;
value: string;
valid: true;
} | {
Expand All @@ -12,12 +18,31 @@ type ReturnType<Float extends SafeIntOrFloat | number> = {
valid: false;
};
type Options = {
/** Minimum input number to be valid */
min?: number;
/** Maximum input number to be valid */
max?: number;
/** Number of decimal input to be valid */
decimalPlaces?: number;
};
declare function decimalInput<Float extends SafeIntOrFloat | number = SafeIntOrFloat>(input: string, opts?: Options): ReturnType<Float>;
declare function validateFloat<Return extends SafeIntOrFloat | number = SafeIntOrFloat>(input: unknown, opts?: Options): input is Return;
/**
* `decimalInput` parses & validates a decimal string returning a valid decimal string & number else invalid.
* @example
```ts
function handleChange(event) {
const decimal = decimalInput(event.target.value)
if(decimal.valid){
setInputValue(decimal.value)
setFloatValue(decimal.float)
}
}
```
*/
declare function decimalInput<F extends SafeIntOrFloat | number = SafeIntOrFloat>(
/** Your inputs value */
value: string, opts?: Options): DecimalInputReturnType<F>;
declare function validateFloat<R extends SafeIntOrFloat | number = SafeIntOrFloat>(input: unknown, opts?: Options): input is R;
declare function isSafeIntOrFloat(input: number): input is SafeIntOrFloat;
export type { SafeIntOrFloat };
declare const DecimalUtil: {
Expand Down
27 changes: 22 additions & 5 deletions dist/decimalInput.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
function decimalInput(input, opts = {}) {
const value = parseInput(input);
const float = Number(value);
const valid = validateInput(value, opts.decimalPlaces) && validateFloat(float, opts);
/**
* `decimalInput` parses & validates a decimal string returning a valid decimal string & number else invalid.
* @example
```ts
function handleChange(event) {
const decimal = decimalInput(event.target.value)
if(decimal.valid){
setInputValue(decimal.value)
setFloatValue(decimal.float)
}
}
```
*/
function decimalInput(
/** Your inputs value */
value, opts = {}) {
const parsedValue = parseInput(value);
const float = Number(parsedValue);
const valid = validateInput(parsedValue, opts.decimalPlaces) &&
validateFloat(float, opts);
return valid
? { float: float, value, valid }
? { float: float, value: parsedValue, valid }
: { float: undefined, value: undefined, valid: false };
}
function validateFloat(input, opts = {}) {
Expand Down
57 changes: 43 additions & 14 deletions src/decimalInput.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
/** @see https://egghead.io/blog/using-branded-types-in-typescript */
/**
* A branded type to allow strong typing of a decimal(float) value.
*
* You can use `isSafeIntOrFloat` to determine if a value or assert with `as SafeIntOrFloat` if you're sure.
*
* @see {@link https://egghead.io/blog/using-branded-types-in-typescript | Branded types explication}
*/
type SafeIntOrFloat = number & { __type: 'SafeIntOrFloat' };

type ReturnType<Float extends SafeIntOrFloat | number> =
type DecimalInputReturnType<F extends SafeIntOrFloat | number> =
| {
float: Float;
float: F;
value: string;
valid: true;
}
Expand All @@ -13,27 +19,50 @@ type ReturnType<Float extends SafeIntOrFloat | number> =
valid: false;
};

type Options = { min?: number; max?: number; decimalPlaces?: number };

function decimalInput<Float extends SafeIntOrFloat | number = SafeIntOrFloat>(
input: string,
type Options = {
/** Minimum input number to be valid */
min?: number;
/** Maximum input number to be valid */
max?: number;
/** Number of decimal input to be valid */
decimalPlaces?: number;
};

/**
* `decimalInput` parses & validates a decimal string returning a valid decimal string & number else invalid.
* @example
```ts
function handleChange(event) {
const decimal = decimalInput(event.target.value)
if(decimal.valid){
setInputValue(decimal.value)
setFloatValue(decimal.float)
}
}
```
*/
function decimalInput<F extends SafeIntOrFloat | number = SafeIntOrFloat>(
/** Your inputs value */
value: string,
opts: Options = {}
): ReturnType<Float> {
const value = parseInput(input);
const float = Number(value);
): DecimalInputReturnType<F> {
const parsedValue = parseInput(value);
const float = Number(parsedValue);

const valid =
validateInput(value, opts.decimalPlaces) && validateFloat(float, opts);
validateInput(parsedValue, opts.decimalPlaces) &&
validateFloat(float, opts);

return valid
? { float: float as Float, value, valid }
? { float: float as F, value: parsedValue, valid }
: { float: undefined, value: undefined, valid: false };
}

function validateFloat<Return extends SafeIntOrFloat | number = SafeIntOrFloat>(
function validateFloat<R extends SafeIntOrFloat | number = SafeIntOrFloat>(
input: unknown,
opts: Options = {}
): input is Return {
): input is R {
if (typeof input !== 'number') {
return false;
}
Expand Down

0 comments on commit 43cb1f4

Please sign in to comment.