vee-type-safe
This is a simple TypeScript type checking utility library.
Requires Typescript version >= 3.2
.
View detailed API documentation generated by TypeDoc
Quick API glance
mismatch(suspect: unknown, typeDescr: TypeDescription)
Returns null
or a MismatchInfo
object that stores information
about type incompatability with the given
TypeDescription
, e.g. why and where suspect
's invalid property is.
This is a powerful tool to generate useful error messages while validating value shape type.
Note: this function doesn't allow suspect
to have properties not listed in typeDescr
which differentiates it from duckMismatch()
(see bellow).
; ; ; ; ; ; if mismatchInfo != null // now you may safely assign untrustedJson to dbDocument: Object.assigndbDocument, untrustedJson;
duckMismatch(suspect, typeDescr)
Works the same way as mismatch(suspect, typeDescr)
but allows suspect
object with excess properties to pass the match.
; Vts.duckMismatch , ; // returns null as suspect is allowed to have excess properties ; ; // Here we map the given type description shape to the type that it describes statically ; /* ExpectedJson === { client: string; walletNumber: string; } */ ; if mismatchInfo != null // ^~~~ Vts.ensureDuckMatch() does the same ; // process client
What is TypeDescription?
Type description is a simple JavaScript object with values of TypeDescription
type or basic typename string ('string'
,
'number'
, 'function'
...) or Set<TypeDescription>
or TypeDescription[]
or RegExp
or your
custom TypePredicate
function. TypeDescription
is actually a conditional (dependent on type argument) union type of all of these.
Here is an example of how you may describe your type.
; Vts.conforms,; // true Vts.conforms, ; // true ; // generate static TypeScript type:; // type Human === { // name: string;// id: number;// }
Here is an actual algorithm how conforms()
function interprets TypeDescription
.
- If it is a basic JavaScript typename string (should satisfy typeof operator
domain definition), then function returns
typeof suspect === typeDescr
. - If it is a
RegExp
, then returnstypeof suspect === 'string' && typeDescr.test(suspect)
. - If it is a
Set<TypeDescription>
, returnstrue
if suspect conforms to at least one of the given TDs inSet
. - If it is an
Array<TypeDescription>
and it consists of one item, returnstrue
ifsuspect
isArray
and each of its items conforms to the given TD attypeDescr[0]
. - If it is an
Array<TypeDescription>
and it consists of more than one item, returnstrue
if suspect isArray
andsuspect.length === typeDescr.length
and each correspondingsuspect[i]
conforms totypeDescr[i]
type description. - If it is an empty
Array
, returnstrue
ifsuspect
isArray
of any type. - If it is an object, returns
true
ifsuspect
is also an object and eachtypeDescr[key]
is a TD forsuspect[key]
. Excess properties insuspect
do not matter forconforms()
function, but matter forexactlyConforms()
andmismatch()
functions. - If it is a
TypePredicate
(i.e.(suspect: unknown) => boolean
), then returnstypeDescr(suspect)
.
Predefined TypeDescriptions
There are factory functions that return TypeDescription
s (those are often TypePredicate
s) or already defined TypePredicates
, that you should use as type descriptions when calling mismatch/duckMismatch/conforms/exactlyConforms(suspect, typeDescr)
.
TypePredicate
is a function of type:
(suspect: unknown) => boolean
If you specify a generic argument TTarget
it becomes a true TypeScript type predicate, so that you will be able to get described type from it when using Vts.TypeDescriptionTarget
:
(suspect: unknown) => suspect is TTarget
isNumberWithinRange(min, max)
Returns a predicate that returns true if its argument is a number within the range [min
, max
] or [max
, min
] if min > max
.
; Vts.conforms,; // false
isIntegerWithinRange(min, max)
The same as isNumberWithinRange(min, max)
, but its returned predicate returns false if forwarded argument is not an integer.
optional(typeDescr: TypeDescription)
Retuns Set(['undefined', typeDescr]))
;Vts.conforms, // return false because the property is not undefined, // but doesn't conform to 'number' typeVts.conforms,;// returns true because the property is not undefined// and conforms to isNegativeInteger restrictionVts.conforms,;// returns true because property 'prop' may be absent
Self explanatory functions
All these functions take unknown
type argument and return suspect is number
, which is useful as a type guard or when using as a type description.
isInteger(suspect)
isPositiveInteger(suspect)
isNegativeInteger(suspect)
isPositiveNumber(suspect)
isNegativeNumber(suspect)
isZeroOrPositiveInteger(suspect)
isZeroOrNegativeInteger(suspect)
isZeroOrPositiveNumber(suspect)
isZeroOrNegativeNumber(suspect)
- ...
;Vts.conforms,; // true
isOneOf<T>(possibleValues: T[])
Returns a predicate that accepts a suspect of any
type and matches it to
one of the provided possible values by
possibleValues.includes(suspect)
. Don't confuse it with new Set(possibleValues)
when forwarding as a type description to conforms()
function, because possibleValues
are not TDs, but values to match with.
; Vts.conforms2, Vts.isOneOf; // trueVts.conforms2, new Set; // compile error// Set<numbers> is not a Set<TypeDescritpion>
Convenient type definitions
interface BasicObject<T>
A shorthand for { [key: string]: T; }
type.
type PrimitiveType
A union of all primitive types (null
is treated as a primitive type).
type BasicTypeName
A union type of string literals which are in typeof
operator domain definition ('string' | 'boolean' | 'object' ...
).
vee-type-safe/express (BETA)
This is a library for ExpressJS routing middleware functions.
ensureTypeMatch(getRequestProperty, typeDescr, makeError?)
Returns express.Handler
that exactly matches the value returned by getRequestProperty(req)
to typeDescr
and if it fails, calls next(makeError(failedTypeInfo))
.
Thus you can be sure that the property of express.Request
object was type checked before using it in your middleware.
Does type matching via core library mismatch()
function.
getRequestProperty: (req: express.Request) => unknown
- this function must return a suspect to match totypeDescr
, based on the givenreq
argument.typeDescr
- type description that the value returned bygetRequestProperty(req)
will be checked to match tomakeError?: (failInfo: MismatchInfo) => unknown
- it is an optional function which makes a custom error to forward tonext()
, by default this function retunsBadTypeStatusError
BadTypeStatusError
is an instance of TypeMismatchError
that has a status: number
property, which is http BAD_REQUEST by default.
; ; ; router.post'api/v1/messages', VtsEx.matchType VtsEx.ReqBody, // or req => req.body (your custom obtaining logic here) , new MyCustomErrormmInfo.path, mmInfo.actualValue , // replaces standard express.Request.body type with MessagesPostRequest ;
There is a list of handy functions to specify as getRequestProperty
argument:
ReqBody(req) => req.body
ReqParams(req) => req.params
ReqQuery(req) => req.query
ReqCookies(req) => req.cookies
ReqHeaders(req) => req.headers
; /* ... */ router.get'api/v1/users/', VtsEx.matchTypeVtsEx.ReqQuery, , ;