Skip to content

Commit

Permalink
Add truthy type guard
Browse files Browse the repository at this point in the history
This adds an explicit type guard for truthiness. Generally you could use the `Boolean` constructor, but typescript doesn't treat that as a type guard right now (see [#16655](microsoft/TypeScript#16655)).
  • Loading branch information
ericbf committed Oct 14, 2020
1 parent 02d0da8 commit bbfab1d
Show file tree
Hide file tree
Showing 10 changed files with 36 additions and 37 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fast-ts-helpers",
"version": "0.0.0-dev.4",
"version": "0.0.0-dev.5",
"private": true,
"description": "A package containing some helpful functions, constants, types, and react hooks.",
"license": "MIT",
Expand Down
9 changes: 0 additions & 9 deletions src/BooleanConstructor.d.ts

This file was deleted.

3 changes: 2 additions & 1 deletion src/cacheKey.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import stringify from "json-stable-stringify"

import { truthy } from "./truthy"
import { uuid } from "./uuid"

/**
Expand Down Expand Up @@ -35,7 +36,7 @@ export function cacheKey<Type>(obj: Type) {
}

function hasCacheKey<T>(obj: T): obj is T & { __cacheKey: string } {
return Boolean(obj) && `__cacheKey` in obj
return truthy(obj) && `__cacheKey` in obj
}

return stringify(obj, { replacer })
Expand Down
21 changes: 10 additions & 11 deletions src/concatUrls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ import { FalsibleList } from "./FalsibleList"
/** Concatenate the passed URL parts into one URL using `/` as the separator, with a leadin slash and without a trailing slash. */
export function concatUrls(...urls: FalsibleList<string>[]) {
const filtered = flatfilter(urls)
let protocol = ``

const first = filtered[0]
if (filtered.length > 0) {
let protocol = ``
const first = filtered[0]

if (Boolean(first) && /^https?:\/\//.test(first)) {
protocol = /^https?:\//.exec(first)![0]
filtered[0] = first.replace(/^https?:\/\//, ``)
if (/^https?:\/\//.test(first)) {
protocol = /^.+?:\/(?=\/)/.exec(first)![0]
filtered[0] = first.replace(/^.+?:\/\//, ``)
}

return `${protocol}/${filtered.join(`/`).replace(/^\/+|\/+$|\/+(\/)/g, `$1`)}`
}

return (
protocol +
(filtered.length > 0
? `/${filtered.join(`/`).replace(/^\/+|\/+$|\/+(\/)/g, `$1`)}`
: ``)
)
return ``
}
5 changes: 3 additions & 2 deletions src/focus.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { focusableSelector } from "./focusableSelector"
import { Falsible } from "./Falsible"
import { focusableSelector } from "./focusableSelector"
import { truthy } from "./truthy"

/**
* Transfer the focus to an element, optionally preventing scrolling. You can use this to focus on elements that aren't actually focusable too, for accessibility.
Expand All @@ -8,7 +9,7 @@ import { Falsible } from "./Falsible"
* @param preventScroll Whether scrolling should be prevented. Defaults to `true`.
*/
export function focus(element: Falsible<HTMLElement | SVGElement>, preventScroll = true) {
if (!Boolean(element)) {
if (!truthy(element)) {
return
}

Expand Down
6 changes: 3 additions & 3 deletions src/onEnterKeyDown.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Falsible } from "./Falsible"

import { onNonRepeatedKeyDown } from "./onNonRepeatedKeyDown"
import { memoize } from "./memoize"
import { onNonRepeatedKeyDown } from "./onNonRepeatedKeyDown"
import { truthy } from "./truthy"

/**
* Respond to the event where the user presses the enter key, responding only to the actula press, not the repeated events if the user holds it.
Expand All @@ -19,7 +19,7 @@ export const onEnterKeyDown = memoize(
) => {
return onNonRepeatedKeyDown(
(event) => {
if (event.key === `Enter` && Boolean(action)) {
if (event.key === `Enter` && truthy(action)) {
action(event)
}
},
Expand Down
10 changes: 5 additions & 5 deletions src/onNonRepeatedKeyDown.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Falsible } from "./Falsible"

import { memoize } from "./memoize"
import { combine } from "./combine"
import { deleteOwnProperties } from "./deleteOwnProperties"
import { Falsible } from "./Falsible"
import { memoize } from "./memoize"
import { truthy } from "./truthy"

/** The keys that are currently pressed. */
const keysDown: Record<string, boolean> = {}
Expand All @@ -23,7 +23,7 @@ export const onNonRepeatedKeyDown = memoize(
) => {
return {
onKeyDown: combine(
Boolean(action) &&
truthy(action) &&
((event: React.KeyboardEvent) => {
if (!keysDown[event.key]) {
keysDown[event.key] = true
Expand All @@ -34,7 +34,7 @@ export const onNonRepeatedKeyDown = memoize(
extraOnKeyDown
),
onKeyUp: combine(
Boolean(action) &&
truthy(action) &&
((event: React.KeyboardEvent) => {
if (event.key === `Meta`) {
deleteOwnProperties(keysDown)
Expand Down
10 changes: 6 additions & 4 deletions src/parseDate.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { truthy } from "./truthy"

/**
* Parse a date, number, or string into a Date.
*
Expand Down Expand Up @@ -41,7 +43,7 @@ export function parseDate(date: string | number | Date | undefined) {
}

// If the datePart is set, parse that date part
if (Boolean(datePart)) {
if (truthy(datePart)) {
const [rawYear, rawMonth, rawDay] = datePart.split(`-`).map(parseFloat)

year = rawYear
Expand All @@ -58,7 +60,7 @@ export function parseDate(date: string | number | Date | undefined) {
let zoneHalf: string | undefined

// If the time part is defined, get the hour, minute, and second values
if (Boolean(timePart)) {
if (truthy(timePart)) {
const parts = timePart.split(/Z|\+|(?=-)/)

const timeHalf = parts[0]!
Expand All @@ -82,12 +84,12 @@ export function parseDate(date: string | number | Date | undefined) {
const manualTime = new Date(year, month, day, hours, minutes, seconds).getTime()

// If the time part is defined, assume UTC. The other if statement below will offset accordingly.
if (Boolean(timePart)) {
if (truthy(timePart)) {
offset = now.getTimezoneOffset() * 60 * 1000
}

// If the zone half of the time part is defined, do that offset here
if (Boolean(zoneHalf)) {
if (truthy(zoneHalf)) {
const [offsetHours, offsetMinutes] = zoneHalf.split(`:`).map(parseFloat)

offset += offsetHours * 60 * 60 * 1000
Expand Down
5 changes: 5 additions & 0 deletions src/truthy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Falsible } from "./Falsible"

export function truthy<T>(value?: Falsible<T>): value is T {
return Boolean(value)
}

0 comments on commit bbfab1d

Please sign in to comment.