Skip to content

Commit

Permalink
feat: support sync calls in tryit function (#312)
Browse files Browse the repository at this point in the history
  • Loading branch information
sodiray authored Jun 27, 2023
1 parent c378bd1 commit 1817ace
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 7 deletions.
24 changes: 19 additions & 5 deletions src/async.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fork, list, range, sort } from './array'
import { isArray } from './typed'
import { isArray, isPromise } from './typed'

/**
* An async reduce function. Works like the
Expand Down Expand Up @@ -262,13 +262,27 @@ export const sleep = (milliseconds: number) => {
export const tryit = <Args extends any[], Return>(
func: (...args: Args) => Return
) => {
return async (
return (
...args: Args
): Promise<[Error, undefined] | [undefined, Awaited<Return>]> => {
): Return extends Promise<any>
? Promise<[Error, undefined] | [undefined, Awaited<Return>]>
: [Error, undefined] | [undefined, Return] => {
try {
return [undefined, await func(...args)]
const result = func(...args)
if (isPromise(result)) {
return result
.then(value => [undefined, value])
.catch(err => [err, undefined]) as Return extends Promise<any>
? Promise<[Error, undefined] | [undefined, Awaited<Return>]>
: [Error, undefined] | [undefined, Return]
}
return [undefined, result] as Return extends Promise<any>
? Promise<[Error, undefined] | [undefined, Awaited<Return>]>
: [Error, undefined] | [undefined, Return]
} catch (err) {
return [err as any, undefined]
return [err as any, undefined] as Return extends Promise<any>
? Promise<[Error, undefined] | [undefined, Awaited<Return>]>
: [Error, undefined] | [undefined, Return]
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export {
isNumber,
isObject,
isPrimitive,
isPromise,
isString,
isSymbol
} from './typed'
22 changes: 20 additions & 2 deletions src/tests/async.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,10 @@ describe('async module', () => {

describe('_.try function', () => {
test('returns error when error is thrown', async () => {
const [err, result] = await _.try(async () => {
const fn = _.try(async () => {
throw new Error('not good enough')
})()
})
const [err, result] = await fn()
assert.isUndefined(result)
assert.isNotNull(err)
assert.equal(err!.message, 'not good enough')
Expand All @@ -242,6 +243,23 @@ describe('async module', () => {
assert.isNotNull(result)
assert.equal(result, 'hello')
})
test('handles non-async function results', async () => {
const [err, result] = _.try(() => {
return 'hello'
})()
assert.isUndefined(err)
assert.isNotNull(result)
assert.equal(result, 'hello')
})
test('handles non-async function errors', async () => {
const [err, result] = _.try(() => {
if (1 < 0) return ''
throw new Error('unknown')
})()
assert.isUndefined(result)
assert.isNotNull(err)
assert.equal(err!.message, 'unknown')
})
test('alias exists', () => {
assert.isNotNull(_.tryit)
})
Expand Down
20 changes: 20 additions & 0 deletions src/tests/typed.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,26 @@ describe('typed module', () => {
})
})

describe('isPromise function', () => {
test('return true for Promise values', () => {
assert.isTrue(_.isPromise(new Promise(res => res(0))))
assert.isTrue(_.isPromise(new Promise(res => res(''))))
assert.isTrue(_.isPromise((async () => {})()))
})
test('return false for non-Date values', () => {
assert.isFalse(_.isPromise(22))
assert.isFalse(_.isPromise({ name: 'x' }))
assert.isFalse(_.isPromise('abc'))
assert.isFalse(_.isPromise(String('abc')))
assert.isFalse(_.isPromise([1, 2, 3]))
assert.isFalse(_.isPromise(function work() {}))
assert.isFalse(_.isPromise(() => {}))
assert.isFalse(_.isPromise(Symbol('')))
assert.isFalse(_.isPromise(Symbol('hello')))
assert.isFalse(_.isPromise({ then: 2 }))
})
})

describe('isSymbol function', () => {
test('returns false for null', () => {
const input = null
Expand Down
12 changes: 12 additions & 0 deletions src/typed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ export const isDate = (value: any): value is Date => {
return Object.prototype.toString.call(value) === '[object Date]'
}

/**
* This is really a _best guess_ promise checking. You
* should probably use Promise.resolve(value) to be 100%
* sure you're handling it correctly.
*/
export const isPromise = (value: any): value is Promise<any> => {
if (!value) return false
if (!value.then) return false
if (!isFunction(value.then)) return false
return true
}

export const isEmpty = (value: any) => {
if (value === true || value === false) return true
if (value === null || value === undefined) return true
Expand Down

1 comment on commit 1817ace

@vercel
Copy link

@vercel vercel bot commented on 1817ace Jun 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.