src/numeric: New module
This beings to introduce compile-time safety for numeric values under the assumption that they are enforced by the runtime. See docblock for more information.master
parent
7583cc1a71
commit
e2edbfc7b2
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* Numeric types
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010-2019 R-T Specialty, LLC.
|
||||||
|
*
|
||||||
|
* This file is part of the Liza Data Collection Framework.
|
||||||
|
*
|
||||||
|
* liza is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* TypeScript's type system does not support algebraic numeric domains. A
|
||||||
|
* compromise is to provide nominal types that allow developers to assume
|
||||||
|
* that some constraint has been met, and then ensure that the type is only
|
||||||
|
* ever asserted when that constraint is explicitly validated at
|
||||||
|
* runtime. This allows us to have compile-time checks on numeric values
|
||||||
|
* under the assumption that the runtime will enforce them.
|
||||||
|
*
|
||||||
|
* For this to work, _it is important to always use type predicates_;
|
||||||
|
* if you explicit cast to one of these numeric types, it circumvents the
|
||||||
|
* safety provided by the system and may introduce nasty bugs, since users
|
||||||
|
* of these types assume the provided data has already been validated.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any number ≥ 0
|
||||||
|
*
|
||||||
|
* This is useful for array indexing.
|
||||||
|
*/
|
||||||
|
export type PositiveInteger = NominalType<number, 'PositiveInteger'>;
|
||||||
|
|
||||||
|
|
||||||
|
/** Whether the given number is suitable as a PositiveInteger */
|
||||||
|
export const isPositiveInteger = ( n: number ): n is PositiveInteger => n >= 0;
|
|
@ -0,0 +1,59 @@
|
||||||
|
/**
|
||||||
|
* Test numeric types
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010-2019 R-T Specialty, LLC.
|
||||||
|
*
|
||||||
|
* This file is part of the Liza Data Collection Framework.
|
||||||
|
*
|
||||||
|
* liza is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { PositiveInteger, isPositiveInteger } from "../src/numeric";
|
||||||
|
|
||||||
|
|
||||||
|
describe( 'isPositiveInteger', () =>
|
||||||
|
{
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
5,
|
||||||
|
].forEach( value => it( `accepts positive integers (${value})`, () =>
|
||||||
|
{
|
||||||
|
expect( isPositiveInteger( value ) ).to.be.true;
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
|
||||||
|
[
|
||||||
|
-1,
|
||||||
|
-5,
|
||||||
|
].forEach( value => it( `rejects negative integers (${value})`, () =>
|
||||||
|
{
|
||||||
|
expect( isPositiveInteger( value ) ).to.be.false;
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
|
||||||
|
it( "asserts type PositiveInteger", () =>
|
||||||
|
{
|
||||||
|
const n = 5;
|
||||||
|
|
||||||
|
if ( isPositiveInteger( n ) )
|
||||||
|
{
|
||||||
|
// TS should recognize as PositiveInteger within this block
|
||||||
|
checkPositiveInteger( n );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
const checkPositiveInteger = ( _n: PositiveInteger ): void => {};
|
Loading…
Reference in New Issue