Skip to content

Commit

Permalink
Merge pull request #11 from cuppachino/add-test-cases
Browse files Browse the repository at this point in the history
add test cases
  • Loading branch information
cuppachino committed Sep 6, 2023
2 parents 0d29bcd + 41402f2 commit 51e83ec
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/sharp-ducks-travel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cuppachino/proxy-fn": patch
---

add test cases and fix bug with nested Promise<T> types
5 changes: 4 additions & 1 deletion src/modules/proxy-fn.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import type { Assigned } from '../types/assigned.js'
import type { DefinitelyAwaited } from '../types/definitely-awaited.js'
import type { If } from '../types/if.js'
import type { IsEmpty } from '../types/is-empty.js'
import type { IsPromise } from '../types/is-promise.js'
import type { MaybePromise } from '../types/maybe-promise.js'
import { isPromise } from '../utils/is-promise.js'

Expand All @@ -14,7 +17,7 @@ export type ProxyFnHandler<Fn extends (...args: any[]) => any> = <
}>
) => ProxyFn<
NewArgs,
[ActualArgs] extends [Promise<infer _>] ? Promise<NewReturnType> : NewReturnType,
If<IsPromise<ActualArgs>, Promise<DefinitelyAwaited<NewReturnType>>, NewReturnType>,
Assigned<Fn>
>

Expand Down
1 change: 1 addition & 0 deletions src/types/definitely-awaited.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type DefinitelyAwaited<T> = T extends Promise<infer U> ? U : T
1 change: 1 addition & 0 deletions src/types/if.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type If<T extends boolean, A, B> = T extends true ? A : B
9 changes: 6 additions & 3 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export type * from './is-never.js'
export type * from './is-empty.js'
export type * from './maybe-promise.js'
export type * from './assigned.js'
export type * from './definitely-awaited.js'
export type * from './if.js'
export type * from './is-empty.js'
export type * from './is-never.js'
export type * from './is-promise.js'
export type * from './maybe-promise.js'
1 change: 1 addition & 0 deletions src/types/is-promise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type IsPromise<T> = T extends Promise<any> ? true : false
89 changes: 78 additions & 11 deletions tests/proxy-fn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { test, expectTypeOf, expect } from 'vitest'

test('proxy function', () => {
const add = (a: number, b: number) => a + b

expectTypeOf(add).toEqualTypeOf((a: number, b: number) => a + b)
expectTypeOf(add).not.toEqualTypeOf<(...args: number[]) => number>()

Expand Down Expand Up @@ -84,12 +84,17 @@ test('proxy function', () => {
})

test('proxy function with properties', () => {
const adder = Object.assign(function _adder(a: number, b: number) { return a + b }, {
hello: 'addAlt',
greet() {
console.log(this.hello)
const adder = Object.assign(
function _adder(a: number, b: number) {
return a + b
},
{
hello: 'addAlt',
greet() {
console.log(this.hello)
}
}
})
)

const b1 = proxyFn(adder)({})
// ^?
Expand All @@ -108,12 +113,74 @@ test('proxy function with properties', () => {
return res
}
})
expectTypeOf(b2).toEqualTypeOf<(() => Promise<number>) & {
hello: string,
greet(): void
}>()
expectTypeOf(b2).toEqualTypeOf<
(() => Promise<number>) & {
hello: string
greet(): void
}
>()
expect(b2.hello).toBe('addAlt')
expect(b2.greet).toBeInstanceOf(Function)
expect(b2()).instanceOf(Promise)
expect(b2()).resolves.toBe(3)
})
})

test('should not return nested promises', () => {
const getInventories = (id: number) =>
Promise.resolve({
ownerId: id,
items: []
})
const getDefaultUser = () => Promise.resolve({ id: 42069 })

const x = proxyFn(getInventories)(
(() => {
let currentId: number | null = null
const getId = async () => {
if (currentId !== null) return currentId
return (currentId = (await getDefaultUser()).id)
}
return {
async from() {
return [await getId()]
},
async to(res) {
return [await res, 'closure'] as const
}
}
})()
)
expectTypeOf(x).toEqualTypeOf<
() => Promise<readonly [{ ownerId: number; items: never[] }, 'closure']>
>()
expect(x()).instanceOf(Promise)
expect(x()).resolves.toHaveLength(2)
expect(x()).resolves.toEqual([{ ownerId: 42069, items: [] }, 'closure'])

const y = proxyFn(getInventories)(
(() => {
const { getId } = new (class {
currentId: number | null = null
getId = async () => {
if (this.currentId !== null) return this.currentId
return (this.currentId = (await getDefaultUser()).id)
}
})()
return {
async from() {
return [await getId()]
},
async to(res) {
return [await res, 'class'] as const
}
}
})()
)

expectTypeOf(y).toEqualTypeOf<
() => Promise<readonly [{ ownerId: number; items: never[] }, 'class']>
>()
expect(y()).instanceOf(Promise)
expect(y()).resolves.toHaveLength(2)
expect(y()).resolves.toEqual([{ ownerId: 42069, items: [] }, 'class'])
})

0 comments on commit 51e83ec

Please sign in to comment.