TypeScript tiny narrowing helpers you better use.
npm i narrowing # yarn add narrowing
let a: unknown;
if (isXXX(a)) {
// TypeScript know your type here!
}
Basic:
- isString
- isNumber
- isBigInt
- isBoolean
- isSymbol
- isUndefined
- isNull
- isNil
- isFunction
- isInstance
- isArray
- isObject
Advanced:
These functions help you make advanced type guards.
import {
isArray,
isBigInt,
isBoolean,
isFunction,
isInstance,
isNil,
isNull,
isNumber,
isObject,
isString,
isSymbol,
isUndefined
} from 'narrowing';
let a: unknown;
if (isString(a)) a.toLocaleLowerCase();
if (isNumber(a)) a.toFixed();
if (isBigInt(a)) a.toString();
if (isBoolean(a)) a.valueOf();
if (isSymbol(a)) a.toString();
if (isUndefined(a)) {
a; // undefined
}
if (isNull(a)) {
a; // null
}
if (isNil(a)) {
a; // null | undefined
}
function testFunc(a: string, b: number): boolean {
return true;
}
if (isFunction<typeof testFunc>(a)) {
a('11', 1); // no error
}
if (isInstance(a, Date)) {
a.getFullYear();
}
class TestClass {
m() {}
}
if (isInstance(a, TestClass)) {
a.m();
}
if (isArray<string>(a)) {
a[0].trim();
}
let b: TestClass | undefined | null;
// b.m(); // Error: Object is possibly 'null' or 'undefined'.ts(2533)
if (!isNil(b)) {
b.m(); // no Error any more
}
if (isObject(a)) {
// let a: {
// [key: string]: unknown;
// };
a;
}
Check if a type has a property
TypeScript Handbook / Using type predicates
type Bird = { fly: () => {} };
type Cat = { run: () => {}; meow: () => {} };
type Dog = { run: () => {} };
let pet = {} as any;
// save these type guards somewhere and reuse them
const isBird = has<Bird>('fly');
const isDogOrCat = has<Dog | Cat>('run');
const isCat = has<Cat>('run', 'meow');
if (isBird(pet)) {
pet.fly(); // Bird
}
if (isDogOrCat(pet)) {
pet.run(); // Dog | Cat
}
if (isCat(pet)) {
pet.meow(); // Cat
}
TypeScript handbook / Discriminated unions
interface Square {
kind: 'square';
size: number;
}
interface Rectangle {
kind: 'rectangle';
width: number;
height: number;
}
interface Circle {
kind: 'circle';
radius: number;
}
const isSquare = kind<Square>('square');
const isRectangle = kind<Rectangle>('circle');
const isCircle = kind<Circle>('circle');
let s = {} as any;
if (isSquare(s)) {
console.log(s.size);
}
if (isRectangle(s)) {
console.log(s.height);
}
if (isCircle(s)) {
console.log(s.radius);
}
const is404 = literal(404);
let code = 200;
if (is404(code)) {
// code's type should be 404 , not number
// let code: 404
code;
}
this is useful when you see schema()
Basic schema validation
let message: unknown = {
code: 200,
msg: 'success',
records: [
{ id: 1, name: 'aaa' },
{ id: 2, name: 'bbb' },
{ id: 3, name: 'ccc' }
]
};
const isSuccess = schema({
code: literal(200),
msg: isString,
records: isArray
});
if (isSuccess(message)) {
// let message: {
// code: 200;
// msg: string;
// records: unknown[];
// }
message;
}
schema supports a type argument for associating a schema with an existing type
interface TestInterface {
id: number;
name: string;
}
const isTestInterface = schema<TestInterface>({
id: isNumber,
name: isString
});
if (isTestInterface(message)) {
// let message: TestInterface
message;
}
Runtime array type validation. Checks each element of an array.
let arr: unknown[] = [1, 2, 3];
if (every(isNumber)(arr)) {
let typeCheck: number[] = arr;
}
Works with any narrowing validator, including schemas.
interface TestInterface {
id: number;
name: string;
}
const isTestInterface = schema<TestInterface>({
id: isNumber,
name: isString
});
let arr: unknown[] = [{ id: 1, name: 'aaa' }];
if (every(isTestInterface)(arr)) {
let typeCheck: TestInterface[] = arr;
}
- 1.1.0
- add
has()
- add
- 1.1.1
has()
accept multiple params
- 1.2.1
- add
kind()
- add
- 1.3.0
- add
isObject()
,isValidObject()
- add
- 1.4.0
- replace
withisValidObject()
schema()
- add
literal()
- replace
- 1.5.0
- add
every()
- add