typescanner
A simple library for implementing Type Guard in TypeScript.
Feature
- 🛡 Basic Type Guard Functions + Custom Type Guard Functions
- 💡 Intuitive definition of Object's type guard functions
- ✨ Verify the type of a value in one line
Demo
https://codesandbox.io/s/typescanner-demo-ke7d4
Install
npm i typescanner
Example
const Lang = {
ja: "ja",
en: "en",
} as const;
type Lang = typeof Lang[keyof typeof Lang];
const langList = Object.values(Lang);
type Post = {
id: number;
author: string | null;
body: string;
lang: Lang;
isPublic: boolean;
createdAt: Date;
tags?: string[] | null;
};
const isPost = scanner<Post>({
id: number,
author: union(string, Null),
body: string,
lang: list(langList),
isPublic: boolean,
createdAt: date,
tags: optional(array(string), Null),
});
const data = {
id: 1,
author: "taro",
body: "Hello!",
lang: "ja",
isPublic: true,
createdAt: new Date(),
tags: ["tag1", "tag2"],
} as unknown;
const post = scan(data, isPost);
post.body;
Usage
fields
fields
is used when creating a scanner
. fields
returns a Condition
or an array of conditions as defined below.
type Condition<T> = (value: unknown) => value is T;
string;
number;
boolean;
symbol;
bigint;
Undefined;
Null;
data;
union(string, null);
union<string | number>(string, number);
array(string);
array<string | number>(string, number);
optional(string);
optional<string | number>(string, number);
list(["a", "b", "c"]);
instanceOf(Error)
scanner
scanner
is a function to implement type guard for objects. It returns a "type guard function" of the type defined by Type Aliase by setting a field to the value of each property.
type Foo = {
a: string;
b: number;
c: boolean;
d: Date;
e: string[];
f?: string;
g: "a" | "b" | "c";
h: string | null;
i: string | number;
j: number;
};
const even = (value: unknown): value is number =>
isNumber(value) && value % 2 === 0;
const isFoo = scanner<Foo>({
a: string,
b: number,
c: boolean,
d: date,
e: array(string),
f: optional(string),
g: list(["a", "b", "c"]),
h: union(string, Null),
i: union<string | number>(string, number),
j: even,
});
const foo = {
a: "a",
b: 2,
c: true,
d: new Date(),
e: ["a", "b"],
f: "f",
g: "a",
j: 2,
} as unknown;
if (isFoo(foo)) {
foo.a
}
Debugging with scannar
If you want to see which field has the problem, set outputLog
to true
.
WARNING: If the scanner is nested, it may not output logs as expected.
const isBar = scanner<Bar>({
a: string,
b: number,
}, { outputLog: true })
if (!isBar(data)) throw new Error("data is invalid")
scan
scan
is used with the first argument being the value you want to validate and the second argument being the Condition
.
If the verification is successful, the "narrowed value" will be returned. If it fails, it throws an exception.
const data = scan(foo as unknown, isFoo);
data.a
const data = scan(bar as unknown, isFoo);
other
Basic type guard functions with function names beginning with "is".
isString("a")
isNumber(1)
isBoolean(true)
isUndefined(undefined)
isNull(null)
isDate(new Data())
isSymbol(Symbol("a"))
isBigint(BigInt(1))
isUnion<string | number>(1, isString, isNumber)
isObject(value)
isArray(["a", "b"], isString)
isArray<string | number>(["a", 1], isString, isNumber)
isArray(["a", null, undefined], isString, isNull, isUndefined)
isOptional("a", isString)
isOptional(undefined, isString)
const Lang = {
ja: "ja",
en: "en",
} as const;
type Lang = typeof Lang[keyof typeof Lang];
const langList = Object.values(Lang);
isList("ja", langList)
try {
...
} catch (error) {
if (isInstanceOf(error, Error)) {
error.message
}
}
Contribution
wellcome
License
MIT