1
0
mirror of https://github.com/robonen/tools.git synced 2026-03-20 10:54:44 +00:00

chore(packages/stdlib): add ts and js utility types

This commit is contained in:
2024-05-03 06:57:46 +07:00
parent 7091352be2
commit 6931fc6f18
11 changed files with 525 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
export * from './js';
export * from './ts';

View File

@@ -0,0 +1,30 @@
import { describe, it, expect } from 'vitest';
import { toString } from './casts';
describe('casts', () => {
describe('toString', () => {
it('correct string representation of a value', () => {
// Primitives
expect(toString(true)).toBe('[object Boolean]');
expect(toString(() => {})).toBe('[object Function]');
expect(toString(5)).toBe('[object Number]');
expect(toString(BigInt(5))).toBe('[object BigInt]');
expect(toString('hello')).toBe('[object String]');
expect(toString(Symbol('foo'))).toBe('[object Symbol]');
// Complex
expect(toString([])).toBe('[object Array]');
expect(toString({})).toBe('[object Object]');
expect(toString(undefined)).toBe('[object Undefined]');
expect(toString(null)).toBe('[object Null]');
expect(toString(/abc/)).toBe('[object RegExp]');
expect(toString(new Date())).toBe('[object Date]');
expect(toString(new Error())).toBe('[object Error]');
expect(toString(new Promise(() => {}))).toBe('[object Promise]');
expect(toString(new Map())).toBe('[object Map]');
expect(toString(new Set())).toBe('[object Set]');
expect(toString(new WeakMap())).toBe('[object WeakMap]');
expect(toString(new WeakSet())).toBe('[object WeakSet]');
});
});
});

View File

@@ -0,0 +1,7 @@
/**
* To string any value.
*
* @param {any} value
* @returns {string}
*/
export const toString = (value: any): string => Object.prototype.toString.call(value);

View File

@@ -0,0 +1,183 @@
import { describe, expect, it } from 'vitest';
import { isArray, isObject, isRegExp, isDate, isError, isPromise, isMap, isSet, isWeakMap, isWeakSet } from './complex';
describe('complex', () => {
describe('isArray', () => {
it('true if the value is an array', () => {
expect(isArray([])).toBe(true);
expect(isArray([1, 2, 3])).toBe(true);
});
it('false if the value is not an array', () => {
expect(isArray('')).toBe(false);
expect(isArray(123)).toBe(false);
expect(isArray(true)).toBe(false);
expect(isArray(null)).toBe(false);
expect(isArray(undefined)).toBe(false);
expect(isArray({})).toBe(false);
expect(isArray(new Map())).toBe(false);
expect(isArray(new Set())).toBe(false);
});
});
describe('isObject', () => {
it('true if the value is an object', () => {
expect(isObject({})).toBe(true);
expect(isObject({ key: 'value' })).toBe(true);
});
it('false if the value is not an object', () => {
expect(isObject('')).toBe(false);
expect(isObject(123)).toBe(false);
expect(isObject(true)).toBe(false);
expect(isObject(null)).toBe(false);
expect(isObject(undefined)).toBe(false);
expect(isObject([])).toBe(false);
expect(isObject(new Map())).toBe(false);
expect(isObject(new Set())).toBe(false);
});
});
describe('isRegExp', () => {
it('true if the value is a regexp', () => {
expect(isRegExp(/test/)).toBe(true);
expect(isRegExp(new RegExp('test'))).toBe(true);
});
it('false if the value is not a regexp', () => {
expect(isRegExp('')).toBe(false);
expect(isRegExp(123)).toBe(false);
expect(isRegExp(true)).toBe(false);
expect(isRegExp(null)).toBe(false);
expect(isRegExp(undefined)).toBe(false);
expect(isRegExp([])).toBe(false);
expect(isRegExp({})).toBe(false);
expect(isRegExp(new Map())).toBe(false);
expect(isRegExp(new Set())).toBe(false);
});
});
describe('isDate', () => {
it('true if the value is a date', () => {
expect(isDate(new Date())).toBe(true);
});
it('false if the value is not a date', () => {
expect(isDate('')).toBe(false);
expect(isDate(123)).toBe(false);
expect(isDate(true)).toBe(false);
expect(isDate(null)).toBe(false);
expect(isDate(undefined)).toBe(false);
expect(isDate([])).toBe(false);
expect(isDate({})).toBe(false);
expect(isDate(new Map())).toBe(false);
expect(isDate(new Set())).toBe(false);
});
});
describe('isError', () => {
it('true if the value is an error', () => {
expect(isError(new Error())).toBe(true);
});
it('false if the value is not an error', () => {
expect(isError('')).toBe(false);
expect(isError(123)).toBe(false);
expect(isError(true)).toBe(false);
expect(isError(null)).toBe(false);
expect(isError(undefined)).toBe(false);
expect(isError([])).toBe(false);
expect(isError({})).toBe(false);
expect(isError(new Map())).toBe(false);
expect(isError(new Set())).toBe(false);
});
});
describe('isPromise', () => {
it('true if the value is a promise', () => {
expect(isPromise(new Promise(() => {}))).toBe(true);
});
it('false if the value is not a promise', () => {
expect(isPromise('')).toBe(false);
expect(isPromise(123)).toBe(false);
expect(isPromise(true)).toBe(false);
expect(isPromise(null)).toBe(false);
expect(isPromise(undefined)).toBe(false);
expect(isPromise([])).toBe(false);
expect(isPromise({})).toBe(false);
expect(isPromise(new Map())).toBe(false);
expect(isPromise(new Set())).toBe(false);
});
});
describe('isMap', () => {
it('true if the value is a map', () => {
expect(isMap(new Map())).toBe(true);
});
it('false if the value is not a map', () => {
expect(isMap('')).toBe(false);
expect(isMap(123)).toBe(false);
expect(isMap(true)).toBe(false);
expect(isMap(null)).toBe(false);
expect(isMap(undefined)).toBe(false);
expect(isMap([])).toBe(false);
expect(isMap({})).toBe(false);
expect(isMap(new Set())).toBe(false);
});
});
describe('isSet', () => {
it('true if the value is a set', () => {
expect(isSet(new Set())).toBe(true);
});
it('false if the value is not a set', () => {
expect(isSet('')).toBe(false);
expect(isSet(123)).toBe(false);
expect(isSet(true)).toBe(false);
expect(isSet(null)).toBe(false);
expect(isSet(undefined)).toBe(false);
expect(isSet([])).toBe(false);
expect(isSet({})).toBe(false);
expect(isSet(new Map())).toBe(false);
});
});
describe('isWeakMap', () => {
it('true if the value is a weakmap', () => {
expect(isWeakMap(new WeakMap())).toBe(true);
});
it('false if the value is not a weakmap', () => {
expect(isWeakMap('')).toBe(false);
expect(isWeakMap(123)).toBe(false);
expect(isWeakMap(true)).toBe(false);
expect(isWeakMap(null)).toBe(false);
expect(isWeakMap(undefined)).toBe(false);
expect(isWeakMap([])).toBe(false);
expect(isWeakMap({})).toBe(false);
expect(isWeakMap(new Map())).toBe(false);
expect(isWeakMap(new Set())).toBe(false);
});
});
describe('isWeakSet', () => {
it('true if the value is a weakset', () => {
expect(isWeakSet(new WeakSet())).toBe(true);
});
it('false if the value is not a weakset', () => {
expect(isWeakSet('')).toBe(false);
expect(isWeakSet(123)).toBe(false);
expect(isWeakSet(true)).toBe(false);
expect(isWeakSet(null)).toBe(false);
expect(isWeakSet(undefined)).toBe(false);
expect(isWeakSet([])).toBe(false);
expect(isWeakSet({})).toBe(false);
expect(isWeakSet(new Map())).toBe(false);
expect(isWeakSet(new Set())).toBe(false);
});
});
});

View File

@@ -0,0 +1,81 @@
import { toString } from '.';
/**
* Check if a value is an array.
*
* @param {any} value
* @returns {value is any[]}
*/
export const isArray = (value: any): value is any[] => Array.isArray(value);
/**
* Check if a value is an object.
*
* @param {any} value
* @returns {value is object}
*/
export const isObject = (value: any): value is object => toString(value) === '[object Object]';
/**
* Check if a value is a regexp.
*
* @param {any} value
* @returns {value is RegExp}
*/
export const isRegExp = (value: any): value is RegExp => toString(value) === '[object RegExp]';
/**
* Check if a value is a date.
*
* @param {any} value
* @returns {value is Date}
*/
export const isDate = (value: any): value is Date => toString(value) === '[object Date]';
/**
* Check if a value is an error.
*
* @param {any} value
* @returns {value is Error}
*/
export const isError = (value: any): value is Error => toString(value) === '[object Error]';
/**
* Check if a value is a promise.
*
* @param {any} value
* @returns {value is Promise<any>}
*/
export const isPromise = (value: any): value is Promise<any> => toString(value) === '[object Promise]';
/**
* Check if a value is a map.
*
* @param {any} value
* @returns {value is Map<any, any>}
*/
export const isMap = (value: any): value is Map<any, any> => toString(value) === '[object Map]';
/**
* Check if a value is a set.
*
* @param {any} value
* @returns {value is Set<any>}
*/
export const isSet = (value: any): value is Set<any> => toString(value) === '[object Set]';
/**
* Check if a value is a weakmap.
*
* @param {any} value
* @returns {value is WeakMap<object, any>}
*/
export const isWeakMap = (value: any): value is WeakMap<object, any> => toString(value) === '[object WeakMap]';
/**
* Check if a value is a weakset.
*
* @param {any} value
* @returns {value is WeakSet<object>}
*/
export const isWeakSet = (value: any): value is WeakSet<object> => toString(value) === '[object WeakSet]';

View File

@@ -0,0 +1,3 @@
export * from './casts';
export * from './primitives';
export * from './complex';

View File

@@ -0,0 +1,101 @@
import { describe, expect, it } from 'vitest';
import { isBoolean, isFunction, isNumber, isBigInt, isString, isSymbol, isUndefined, isNull } from './primitives';
describe('primitives', () => {
describe('isBoolean', () => {
it('true if the value is a boolean', () => {
expect(isBoolean(true)).toBe(true);
expect(isBoolean(false)).toBe(true);
});
it('false if the value is not a boolean', () => {
expect(isBoolean(0)).toBe(false);
expect(isBoolean('true')).toBe(false);
expect(isBoolean(null)).toBe(false);
});
});
describe('isFunction', () => {
it('true if the value is a function', () => {
expect(isFunction(() => {})).toBe(true);
expect(isFunction(function() {})).toBe(true);
});
it('false if the value is not a function', () => {
expect(isFunction(123)).toBe(false);
expect(isFunction('function')).toBe(false);
expect(isFunction(null)).toBe(false);
});
});
describe('isNumber', () => {
it('true if the value is a number', () => {
expect(isNumber(123)).toBe(true);
expect(isNumber(3.14)).toBe(true);
});
it('false if the value is not a number', () => {
expect(isNumber('123')).toBe(false);
expect(isNumber(null)).toBe(false);
});
});
describe('isBigInt', () => {
it('true if the value is a bigint', () => {
expect(isBigInt(BigInt(123))).toBe(true);
});
it('false if the value is not a bigint', () => {
expect(isBigInt(123)).toBe(false);
expect(isBigInt('123')).toBe(false);
expect(isBigInt(null)).toBe(false);
});
});
describe('isString', () => {
it('true if the value is a string', () => {
expect(isString('hello')).toBe(true);
});
it('false if the value is not a string', () => {
expect(isString(123)).toBe(false);
expect(isString(null)).toBe(false);
});
});
describe('isSymbol', () => {
it('true if the value is a symbol', () => {
expect(isSymbol(Symbol())).toBe(true);
});
it('false if the value is not a symbol', () => {
expect(isSymbol(123)).toBe(false);
expect(isSymbol('symbol')).toBe(false);
expect(isSymbol(null)).toBe(false);
});
});
describe('isUndefined', () => {
it('true if the value is undefined', () => {
expect(isUndefined(undefined)).toBe(true);
});
it('false if the value is not undefined', () => {
expect(isUndefined(null)).toBe(false);
expect(isUndefined(123)).toBe(false);
expect(isUndefined('undefined')).toBe(false);
});
});
describe('isNull', () => {
it('true if the value is null', () => {
expect(isNull(null)).toBe(true);
});
it('false if the value is not null', () => {
expect(isNull(undefined)).toBe(false);
expect(isNull(123)).toBe(false);
expect(isNull('null')).toBe(false);
});
});
});

View File

@@ -0,0 +1,65 @@
import { toString } from '.';
/**
* Check if a value is a boolean.
*
* @param {any} value
* @returns {value is boolean}
*/
export const isBoolean = (value: any): value is boolean => typeof value === 'boolean';
/**
* Check if a value is a function.
*
* @param {any} value
* @returns {value is Function}
*/
export const isFunction = <T extends Function>(value: any): value is T => typeof value === 'function';
/**
* Check if a value is a number.
*
* @param {any} value
* @returns {value is number}
*/
export const isNumber = (value: any): value is number => typeof value === 'number';
/**
* Check if a value is a bigint.
*
* @param {any} value
* @returns {value is bigint}
*/
export const isBigInt = (value: any): value is bigint => typeof value === 'bigint';
/**
* Check if a value is a string.
*
* @param {any} value
* @returns {value is string}
*/
export const isString = (value: any): value is string => typeof value === 'string';
/**
* Check if a value is a symbol.
*
* @param {any} value
* @returns {value is symbol}
*/
export const isSymbol = (value: any): value is symbol => typeof value === 'symbol';
/**
* Check if a value is a undefined.
*
* @param {any} value
* @returns {value is undefined}
*/
export const isUndefined = (value: any): value is undefined => toString(value) === '[object Undefined]';
/**
* Check if a value is a null.
*
* @param {any} value
* @returns {value is null}
*/
export const isNull = (value: any): value is null => toString(value) === '[object Null]';

View File

@@ -0,0 +1 @@
export * from './string';

View File

@@ -0,0 +1,43 @@
import { describe, expectTypeOf, it } from 'vitest';
import type { HasSpaces, Trim } from './string';
describe('string', () => {
describe('Trim', () => {
it('remove leading and trailing spaces from a string', () => {
type actual = Trim<' hello '>;
type expected = 'hello';
expectTypeOf<actual>().toEqualTypeOf<expected>();
});
it('remove only leading spaces from a string', () => {
type actual = Trim<' hello'>;
type expected = 'hello';
expectTypeOf<actual>().toEqualTypeOf<expected>();
});
it('remove only trailing spaces from a string', () => {
type actual = Trim<'hello '>;
type expected = 'hello';
expectTypeOf<actual>().toEqualTypeOf<expected>();
});
});
describe('HasSpaces', () => {
it('check if a string has spaces', () => {
type actual = HasSpaces<'hello world'>;
type expected = true;
expectTypeOf<actual>().toEqualTypeOf<expected>();
});
it('check if a string has no spaces', () => {
type actual = HasSpaces<'helloworld'>;
type expected = false;
expectTypeOf<actual>().toEqualTypeOf<expected>();
});
});
});

View File

@@ -0,0 +1,9 @@
/**
* Trim leading and trailing whitespace from `S`
*/
export type Trim<S extends string> = S extends ` ${infer R}` ? Trim<R> : S extends `${infer L} ` ? Trim<L> : S;
/**
* Check if `S` has any spaces
*/
export type HasSpaces<S extends string> = S extends `${string} ${string}` ? true : false;