@bedard/utils
This repository acts as my own personal lodash. It contains a number of utility types and functions that I found myself duplicating between projects. I do not anticipate breaking changes, but I'm also not ruling it out. Upgrade with caution.
Installation
The recommended installation method is via NPM.
npm install @bedard/utils
Alternatively, the functions maybe be accessed via a CDN. When using the CDN, the library will be exposed globally as BedardUtils
.
<script src="https://unpkg.com/@bedard/utils"></script>
Functions
Animation
Color
Math
Utility
addVectors
Add vectors together.
import { addVectors } from '@bedard/utils'
addVectors([1, 2], [3, 4])
View source →
angleFrom
Calculate angled distance from a vector. An angle of 0
degrees will track along the X axis, with positive angles rotating counter-clockwise.
import { angleFrom } from '@bedard/utils'
angleFrom([0, 0], 90, 1)
View source →
bilerp
Bi-linear interpolation between vectors.
import { bilerp } from '@bedard/utils'
bilerp([0, 0], [10, 10], 0.5)
View source →
cols
Chunk a square matrix into columns. Note that the source matrix must be provided in row-major order.
import { cols } from '@bedard/utils'
cols([
0, 1, 2,
3, 4, 5,
6, 7, 8,
])
View source →
createEasingFunction
Create an easing function from cubic-bezier points. Note that the included easing functions do not use this utility. They are simpler mathematical functions, and do not produce quite the same results as easing functions created using this utility.
import { createEasingFunction } from '@bedard/utils'
const linear = createEasingFunction(0, 0, 1, 1)
linear(0.5)
View source →
deepEqual
Deep object comparison.
import { deepEqual } from '@bedard/utils'
deepEqual({ foo: { bar: 1 }}, { foo: { bar: 1 }})
View source →
degreesToRadians
Convert degrees to radians.
import { degreesToRadians } from '@bedard/utils'
degreesToRadians(180)
View source →
easeInSine
Easing function that follows this curve.
import { easeInSine } from '@bedard/utils'
easeInSine(0.5)
View source →
easeOutSine
Easing function that follows this curve.
import { easeOutSine } from '@bedard/utils'
easeOutSine(0.5)
View source →
easeInOutSine
Easing function that follows this curve.
import { easeInOutSine } from '@bedard/utils'
easeInOutSine(0.5)
View source →
easeInQuad
Easing function that follows this curve.
import { easeInQuad } from '@bedard/utils'
easeInQuad(0.5)
View source →
easeOutQuad
Easing function that follows this curve.
import { easeOutQuad } from '@bedard/utils'
easeOutQuad(0.5)
View source →
easeInOutQuad
Easing function that follows this curve.
import { easeInOutQuad } from '@bedard/utils'
easeInOutQuad(0.5)
View source →
easeInCubic
Easing function that follows this curve.
import { easeInCubic } from '@bedard/utils'
easeInCubic(0.5)
View source →
easeOutCubic
Easing function that follows this curve.
import { easeOutCubic } from '@bedard/utils'
easeOutCubic(0.5)
View source →
easeInOutCubic
Easing function that follows this curve.
import { easeInOutCubic } from '@bedard/utils'
easeInOutCubic(0.5)
View source →
easeInQuart
Easing function that follows this curve.
import { easeInQuart } from '@bedard/utils'
easeInQuart(0.5)
View source →
easeOutQuart
Easing function that follows this curve.
import { easeOutQuart } from '@bedard/utils'
easeOutQuart(0.5)
View source →
easeInOutQuart
Easing function that follows this curve.
import { easeInOutQuart } from '@bedard/utils'
easeInOutQuart(0.5)
View source →
easeInQuint
Easing function that follows this curve.
import { easeInQuint } from '@bedard/utils'
easeInQuint(0.5)
View source →
easeOutQuint
Easing function that follows this curve.
import { easeOutQuint } from '@bedard/utils'
easeOutQuint(0.5)
View source →
easeInOutQuint
Easing function that follows this curve.
import { easeInOutQuint } from '@bedard/utils'
easeInOutQuint(0.5)
View source →
easeInExpo
Easing function that follows this curve.
import { easeInExpo } from '@bedard/utils'
easeInExpo(0.5)
View source →
easeOutExpo
Easing function that follows this curve.
import { easeOutExpo } from '@bedard/utils'
easeOutExpo(0.5)
View source →
easeInOutExpo
Easing function that follows this curve.
import { easeInOutExpo } from '@bedard/utils'
easeInOutExpo(0.5)
View source →
easeInCirc
Easing function that follows this curve.
import { easeInCirc } from '@bedard/utils'
easeInCirc(0.5)
View source →
easeOutCirc
Easing function that follows this curve.
import { easeOutCirc } from '@bedard/utils'
easeOutCirc(0.5)
View source →
easeInOutCirc
Easing function that follows this curve.
import { easeInOutCirc } from '@bedard/utils'
easeInOutCirc(0.5)
View source →
easeInBack
Easing function that follows this curve.
import { easeInBack } from '@bedard/utils'
easeInBack(0.5)
View source →
easeOutBack
Easing function that follows this curve.
import { easeOutBack } from '@bedard/utils'
easeOutBack(0.5)
View source →
easeInOutBack
Easing function that follows this curve.
import { easeInOutBack } from '@bedard/utils'
easeInOutBack(0.5)
View source →
easeInElastic
Easing function that creates an elastic-in effect.
import { easeInElastic } from '@bedard/utils'
easeInElastic(0.5)
View source →
easeOutElastic
Easing function that creates an elastic-out effect.
import { easeOutElastic } from '@bedard/utils'
easeOutElastic(0.5)
View source →
easeInOutElastic
Easing function that creates an elastic-in-out effect.
import { easeInOutElastic } from '@bedard/utils'
easeInOutElastic(0.5)
View source →
easeInBounce
Easing function that creates a bounce-in effect.
import { easeInBounce } from '@bedard/utils'
easeInBounce(0.5)
View source →
easeOutBounce
Easing function that creates a bounce-out effect.
import { easeOutBounce } from '@bedard/utils'
easeOutBounce(0.5)
View source →
easeInOutBounce
Easing function that creates a bounce-in-out effect.
import { easeInOutBounce } from '@bedard/utils'
easeInOutBounce(0.5)
View source →
entries
Type safe wrapper around Object.entries
import { entries } from '@bedard/utils'
entries({ foo: 'bar' })
View source →
flattenCols
Flatten an array of columns to a matrix in row-major order.
import { flattenCols } from '@bedard/utils'
flattenCols([
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
])
View source →
flattenRows
Flatten an array of rows to a matrix in row-major order.
import { flattenRows } from '@bedard/utils'
flattenRows([
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
])
View source →
flip
Convert between rows and columns. A good way to visualize this operation is holding a card by the top-left and bottom-right corners and flipping it over.
import { flip } from '@bedard/utils'
flip([
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
])
View source →
hslToRgb
Convert [hue, saturation, lightness, alpha?]
to [red, green, blue, alpha]
values.
import { hslToRgb } from '@bedard/utils'
hslToRgb([0, 1, 0.5])
View source →
intersect
Intersect two-dimensional lines. Returns undefined
if lines are parellel.
import { intersect } from '@bedard/utils'
intersect([[-1, 0], [1, 0]], [[0, 1], [0, -1]])
View source →
isEmail
A fairly permissive email test where the value must be shaped email@domain.tld
, and contain exactly one @
characters.
import { isEmail } from '@bedard/utils'
isEmail('hello@world.com')
View source →
isEven
Test if a number is even.
import { isEven } from '@bedard/utils'
isEven(2)
View source →
keys
Type-safe wrapper around Object.keys
import { keys } from '@bedard/utils'
keys({ foo: 'bar' })
View source →
lerp
Linear interpolation between numbers.
import { lerp } from '@bedard/utils'
lerp(0, 10, 0.5)
View source →
lerpColors
Linear interpolation between colors.
import { lerpColors } from '@bedard/utils'
lerpColors('#000000', '#ffffff')
View source →
lerpVectors
Linear interpolation between two vectors. This function is similar to bilerp
, but for vectors of any size, or even vectors of different sizes.
import { lerpVectors } from '@bedard/utils'
lerpVectors([0, 0, 0], [1, 2, 3], 0.5)
View source →
measure
Measure the distance between two vectors.
import { measure } from '@bedard/utils'
measure([0, 0], [3, 4])
measure([[0, 0], [3, 4]])
View source →
parse
A type-safe wrapper around JSON.parse
. This utility is complimented by stringify
, Json
, and UnwrapJson
.
import { stringify } from '@bedard/utils'
stringify({ foo: 'bar' })
View source →
parseColor
Parse an RGB string to [red, green, blue, alpha]
values. An error will be thrown if the value is not valid.
import { parseColor } from '@bedard/utils'
parseColor('#123456')
View source →
polygon
Create a regular polygon. The first argument defines the number of points, with the second defining the circumradius. Points start from the 12 o'clock position, and rotate counter-clockwise around the origin.
import { polygon } from '@bedard/utils'
polygon(4, 1)
View source →
radiansToDegrees
Convert radians to degrees.
import { radiansToDegrees } from '@bedard/utils'
radiansToDegrees(Math.PI)
View source →
roll
Roll the start of an array forwards or backwards.
import { roll } from '@bedard/utils'
roll([0, 1, 2], 1)
View source →
rgbToHsl
Convert [red, green, blue, alpha?]
to [hue, saturation, lightness, alpha]
values.
import { rgbToHsl } from '@bedard/utils'
rgbToHsl([255, 0, 0])
View source →
rotateMatrix
Rotate a square matrix. Positive values apply clockwise rotations.
import { rotateMatrix } from '@bedard/utils'
rotateMatrix([
0, 1, 2,
3, 4, 5,
6, 7, 8,
], 1)
View source →
rotateVector
Rotate a vector counter-clockwise around the origin.
import { rotateVector } from '@bedard/utils'
rotateVector([0, 1], 90)
View source →
rows
Chunk a square matrix into rows. Note that the source matrix must be provided in row-major order.
import { rows } from '@bedard/utils'
rows([
0, 1, 2,
3, 4, 5,
6, 7, 8,
])
View source →
scale
Multiple a vector by a number.
import { scale } from '@bedard/utils'
scale([1, 2], 2)
View source →
slope
Calculate the slope of a line.
import { slope } from '@bedard/utils'
slope([0, 0], [1, 1])
slope([[0, 0], [1, 1]])
View source →
stringify
A type-safe wrapper around JSON.stringify
. This utility is complimented by parse
, Json
, and UnwrapJson
import { parse, stringify } from '@bedard/utils'
const json = stringify({ foo: 'bar' })
const obj = parse(json)
View source →
stringifyColor
Convert [red, green, blue, alpha?]
values to string using hexadecimal notation.
import { stringifyColor } from '@bedard/utils'
stringifyColor([255, 0, 0])
View source →
toKeyedObjects
Create keyed objects from an array.
import { toKeyedObjects } from '@bedard/utils'
toKeyedObjects([1, 2], 'foo')
View source →
Types
AllEqual<Sources, Value>
BreakWords<T>
Byte
CamelCase<T>
CamelCaseKeys<T>
CamelCaseKeysDeep<T>
Difference<A, B>
Equal<A, B>
Expect<T>
First<T>
Hex
HexColor<T>
Intersection<A, B>
Join<Parts, Delimeter>
Json<T>
KebabCase<T>
KebabCaseKeys<T>
KebabCaseKeysDeep<T>
Last<T>
Line<T>
MapCapitalize<T>
MapLowercase<T>
MapUppercase<T>
Methods<T>
Not<T>
OmitStartsWith<T, U>
OmitType<T, U>
Opaque<T, Token>
OptionalKeys<T, U>
PascalCase<T>
PascalCaseKeys<T>
PascalCaseKeysDeep<T>
PickStartsWith<T, U>
PickType<T, U>
Pop<T>
Properties<T>
RequiredKeys<T, U>
RgbColor<T>
ScreamingSnakeCase<T>
ScreamingSnakeCaseKeys<T>
ScreamingSnakeCaseKeysDeep<T>
Shift<T>
SnakeCase<T>
SnakeCaseKeys<T>
SnakeCaseKeysDeep<T>
Split<Source, Delimeter>
StartsWith<T, U>
SymmetricDifference<A, B>
Transparent<T>
Trim<T>
UnwrapJson<T>
UnwrapOpaque<T>
ValueOf<T>
Vector<T>
Without<A, B>
XOR<A, B>
AllEqual<Sources, Value>
Types true
if all Sources
equal Value
.
import { AllEqual } from '@bedard/utils'
type Good = AllEqual<[1, 1], 1>
type Bad = AllEqual<[1, 2], 1>
View source →
BreakWords<T>
Explode a string by common word breaks. This currently includes spaces, hyphens, underscores, and casing changes.
import { BreakWords } from '@bedard/utils'
type Words = BreakWords<'one twoThree-four'>
View source →
Byte
A union of all numbers that can be represented by a single byte (0 - 255).
import { Byte } from '@bedard/utils'
const n: Byte = 255
View source →
CamelCase<T>
Convert a string to camel case.
import { CamelCase } from '@bedard/utils'
type Str = CamelCase<'foo-bar'>
View source →
CamelCaseKeys<T>
Camel case object keys.
import { CamelCaseKeys } from '@bedard/utils'
type Obj = CamelCaseKeys<{ foo_bar: any }>
View source →
CamelCaseKeysDeep<T>
Deeply camel case object keys.
import { CamelCaseKeysDeep } from '@bedard/utils'
type Obj = CamelCaseKeysDeep<{ foo_bar: { one_two: any }}>
View source →
Difference<A, B>
Elements of A
that are not elements of B
. For unions, this is the same as the Exclude
utility.
import { Difference } from '@bedard/utils'
type Left = Difference<{ a: any, b: any }, { b: any, c: any }>
View source →
Equal<A, B>
Types true
if A
and B
are equal. This is mainly used with Expect
to verify that types are working as expected. See NotEqual
for the inverse of this type.
import { Expect, Equal } from '@bedard/utils'
type Test = Expect<Equal<number, number>>
View source →
Expect<T>
Verify that T
is true
. This allows for assertions to be made using the type system. See Equal
and NotEqual
for more usage examples.
import { Expect } from '@bedard/utils'
type Test = Expect<true>
View source →
First<T>
Extract the first element of a string or array.
import { First } from '@bedard/utils'
type FirstChar = First<'abc'>
type FirstItem = First<[1, 2, 3]>,
View source →
Hex
A hexadecimal character
import { Hex } from '@bedard/utils'
const char: Hex = 'a'
View source →
HexColor<T>
Validate a hexadecimal color value
import { HexColor } from '@bedard/utils'
const color = <T>(val: HexColor<T>) => val
color('#abc')
View source →
Intersection<A, B>
The intersection of A
and B
, giving preference to A
.
import { Intersection } from '@bedard/utils'
type Shared = Intersection<{ a: any, b: number }, { c: string, d: any }>
View source →
Join<Parts, Delimeter>
Join Parts
by Delimeter
. This type is the opposite of Split
.
import { Join } from '@bedard/utils'
type Str = Join<['a', 'b', 'c']>
type Parts = Join<['a', 'b', 'c'], '.'>
View source →
Json<T>
Encodes a JSON string with underlying type information. This utility is complimented by parse
, stringify
, and UnwrapJson
.
import { Json } from '@bedard/utils'
type UserJson = Json<{ foo: 'bar' }>
View source →
KebabCase<T>
Convert a string to kebab case.
import { KebabCase } from '@bedard/utils'
type Str = KebabCase<'fooBar'>
View source →
KebabCaseKeys<T>
Kebab case object keys.
import { KebabCaseKeys } from '@bedard/utils'
type Obj = KebabCaseKeys<{ foo_bar: any }>
View source →
KebabCaseKeysDeep<T>
Deeply kebab case object keys.
import { KebabCaseKeysDeep } from '@bedard/utils'
type Obj = KebabCaseKeysDeep<{ foo_bar: { one_two: any }}>
View source →
Last<T>
Extract the last element of a string or array.
import { Last } from '@bedard/utils'
type LastChar = Last<'abc'>
type LastItem = Last<[1, 2, 3]>,
View source →
Line<T>
Describes a straight line between two vectors of length T
.
import { Line } from '@bedard/utils'
type Line2D = Line<2>
View source →
MapCapitalize<T>
Capitalize the first letter of each string.
import { MapCapitalize } from '@bedard/utils'
type Capitalized = MapLowercase<['foo', 'bar']>
View source →
MapLowercase<T>
Map strings to lowercase.
import { MapLowercase } from '@bedard/utils'
type Lower = MapLowercase<['A', 'B']>
View source →
MapUppercase<T>
Map strings to uppercase.
import { MapUppercase } from '@bedard/utils'
type Upper = MapUppercase<['a', 'b']>
View source →
Methods<T>
Create a string union of methods from T
. This is the inverse of Properties<T>
import { Methods } from '@bedard/utils'
type Foo = Methods<{ foo: string, bar(): any }>
View source →
Not<T>
Reverse the boolean value of T
.
import { Not } from '@bedard/utils'
type Test = Not<true>
View source →
OmitStartsWith<T, U>
Omit keys of T
that start with U
.
import { OmitStartsWith } from '@bedard/utils'
type Foo = OmitStartsWith<{ FooOne: void; FooTwo: void; BarThree: void }, 'Bar'>
View source →
OmitType<T, U>
Omit keys of T
that extend U
. This is the inverse of PickType<T, U>
.
import { OmitType } from '@bedard/utils'
type Foo = OmitType<{ foo: string, bar: number }, string>
View source →
Opaque<T, Token>
Opaque type T
with an optional Token
. For more on opaque types, this article is a great place to start.
import { Opaque } from '@bedard/utils'
type USD = Opaque<number, 'usd'>
const dollars = 5 as USD
View source →
OptionalKeys<T, U>
Get optional keys from T
, or make keys U
of T
optional.
import { OptionalKeys } from '@bedard/utils'
type Keys = OptionalKeys<{ foo?: any, bar: any }>
type Obj = OptionalKeys<{ foo: any, bar: any }, 'foo'>
View source →
PascalCase<T>
Convert a string to pascal case.
import { PascalCase } from '@bedard/utils'
type Str = PascalCase<'foo-bar'>
View source →
PascalCaseKeys<T>
Kebab case object keys.
import { PascalCaseKeys } from '@bedard/utils'
type Obj = PascalCaseKeys<{ foo_bar: any }>
View source →
PascalCaseKeysDeep<T>
Deeply pascal case object keys.
import { PascalCaseKeysDeep } from '@bedard/utils'
type Obj = PascalCaseKeysDeep<{ foo_bar: { one_two: any }}>
View source →
PickStartsWith<T, U>
Pick keys of T
that start with U
.
import { PickStartsWith } from '@bedard/utils'
type Obj = PickStartsWith<{ FooOne: void; FooTwo: void ; Bar: void }, 'Foo'>
View source →
PickType<T, U>
Pick keys of T
that extend U
. This is the inverse of OmitType<T, U>
.
import { PickType } from '@bedard/utils'
type Obj = PickType<{ foo: string, bar: number }, string>
View source →
Pop<T>
Remove the last element of T
.
import { Pop } from '@bedard/utils'
type Items = Pop<['foo', 'bar', 'baz']>
View source →
Properties<T>
Create a string union of properties from T
. This is the inverse of Methods<T>
.
import { Properties } from '@bedard/utils'
type Foo = Properties<{ foo: string, bar(): any }>
View source →
RequiredKeys<T, U>
Get required keys from T
, or make keys U
of T
required.
import { RequiredKeys } from '@bedard/utils'
type Keys = RequiredKeys<{ foo: any, bar?: any }>
type Obj = RequiredKeys<{ foo?: any, bar?: any }, 'foo'>
View source →
RgbColor<T>
Validate a rgb color
import { RgbColor } from '@bedard/utils'
const rgb = <T>(color: RgbColor<T>) => color
rgb('rgb(0, 0, 0)')
View source →
ScreamingSnakeCase<T>
Convert a string to screaming snake case.
import { ScreamingSnakeCase } from '@bedard/utils'
type Str = ScreamingSnakeCase<'fooBar'>
View source →
ScreamingSnakeCaseKeys<T>
Screaming snake case object keys.
import { ScreamingSnakeCaseKeys } from '@bedard/utils'
type Obj = ScreamingSnakeCaseKeys<{ foo_bar: any }>
View source →
ScreamingSnakeCaseKeysDeep<T>
Deeply screaming snake case object keys.
import { ScreamingSnakeCaseKeysDeep } from '@bedard/utils'
type Obj = ScreamingSnakeCaseKeysDeep<{ foo_bar: { one_two: any }}>
View source →
Shift<T>
Remove the first element of T
.
import { Shift } from '@bedard/utils'
type Items = Shift<['foo', 'bar', 'baz']>
View source →
SnakeCase<T>
Convert a string to snake case.
import { SnakeCase } from '@bedard/utils'
type Str = SnakeCase<'fooBar'>
View source →
SnakeCaseKeys<T>
Snake case object keys.
import { SnakeCaseKeys } from '@bedard/utils'
type Obj = SnakeCaseKeys<{ fooBar: any }>
View source →
SnakeCaseKeysDeep<T>
Deeply snake case object keys.
import { SnakeCaseKeysDeep } from '@bedard/utils'
type Obj = SnakeCaseKeysDeep<{ fooBar: { oneTwo: any }}>
View source →
Split<Source, Delimeter>
Split Source
by Delimeter
. This type is the opposite of Join
. Note that to split by multiple delimeters the second argument must be a string[]
, as unions will create a distributive conditional type.
import { Split } from '@bedard/utils'
type Characters = Split<'abc'>
type SingleDelimeter = Split<'a.b.c', '.'>
type MultipleDelimeters = Split<'a.b-c', ['.', '-']>
View source →
StartsWith<T, U>
Types true
if T
starts with U
.
import { StartsWith } from '@bedard/utils'
type Foo = StartsWith<'FooBar', 'Foo'>
View source →
SymmetricDifference<A, B>
The symmetric difference of A
and B
.
import { SymmetricDifference } from '@bedard/utils'
type OuterSet = SymmetricDifference<'a' | 'b', 'b' | 'c'>
type OuterObj= SymmetricDifference<{ a: any, b: any }, { b: any, c: any }>
View source →
Transparent<T>
A type that does not encode any additional data. This is the inverse of Opaque<T>
.
import { Transparent } from '@bedard/utils'
type NonOpaqueString = Transparent<string>
View source →
Trim<T>
Trim leading and trailing whitespace
import { Trim } from '@bedard/utils'
type Foo = Trim<' foo bar '>
View source →
UnwrapOpaque<T>
Unwrap the underlying data of an Opaque<T>
type.
import { UnwrapOpaque } from '@bedard/utils'
type Foo = Opaque<string, 'example'>
type Bar = UnwrapOpaque<Foo>
View source →
UnwrapJson<T>
Decodes type information from a Json<T>
string.
import { Json, UnwrapJson } from '@bedard/utils'
type UserJson = Json<{ email: string }>
type User = UnwrapJson<UserJson>
View source →
ValueOf<T>
Generate a union from the values of T
.
import { ValueOf } from '@bedard/utils'
type ArrayValues = ValueOf<Array<string>>
type ObjectValues = ValueOf<{ foo: number, bar: string }>
View source →
Vector<T>
Generate a uniform tuple of length T
, with numeric values by default.
import { Vector } from '@bedard/utils'
type Coordinate = Vector<3>
type Things = Vector<3, Thing>
View source →
Without<A, B>
Prohibit properties of A
and omit properties of B
.
import { Without } from '@bedard/utils'
type FooWithoutBar = Without<{ foo: any, bar: any }, { bar: any }>
View source →
XOR<A, B>
Create an exclusive or between two types. Note that for objects, this differs from a union type in that keys are strictly matched.
import { XOR } from '@bedard/utils'
type FooOrBar = XOR<{ foo: any }, { bar: any }>
const a: FooOrBar = { foo }
const b: FooOrBar = { bar }
const c: FooOrBar = { foo, bar }
Additionally, a tuple can be provided for a chained XOR.
type ValidNumber = XOR<[1, 2, 3]>
const a: ValidNumber = 1
const b: ValidNumber = 2
const c: ValidNumber = 3
const d: ValidNumber = 4
View source →
License
MIT
Copyright (c) 2021-present, Scott Bedard