This is how you define the PositiveInteger
dependent type in TypeScript without using type predicate functions or branded (tagged) types:
type PositiveInteger<T extends number> =
`${T}` extends '0' | `-${any}` | `${any}.${any}` ? never : T
It can then be used as follows:
function test<T extends number>(n: PositiveInteger<T>) { /***/ }
The function's argument will be correctly checked at compile time, as shown here:
Things that can't be checked at compile time, such as variables, are passed through. This is obviously unsolvable without resorting to runtime checks (type predicates), because TypeScript types don't exist at runtime.
Similarly, a non-negative integer type, aka unsigned int
, can be defined as follows:
type NonnegativeInteger<T extends number> =
`${T}` extends `-${any}` | `${any}.${any}` ? never : T
Both the PositiveInteger
and NonnegativeInteger
types will be available in the next version (0.1.10) of natlib. They can be found in the prelude
module.
// npm i natlib
import type { PositiveInteger, NonnegativeInteger } from './node_modules/natlib/prelude'
Implementation note: all instances of any
in the template literal types can be changed to string
or even infer _
— this shouldn't matter.