Skip to content

Commit 5a874f1

Browse files
committed
🔧 fix: #1410 handle union derive/resolve property
1 parent 81ea3aa commit 5a874f1

File tree

4 files changed

+73
-40
lines changed

4 files changed

+73
-40
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# 1.4.6 - 15 Sep 2025
22
Improvement:
3-
- strictly check for 200 inline status code
3+
- [#1406](https://github.com/elysiajs/elysia/issues/1406) strictly check for 200 inline status code
44
- coerce union status value and return type
5+
- add `BunHTMLBundleLike` to Elysia inline handler
6+
7+
Bug fix:
8+
- [#1410](https://github.com/elysiajs/elysia/issues/1410) handle union derive/resolve
59

610
# 1.4.5 - 15 Sep 2025
711
Improvement:

example/a.ts

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,19 @@
1-
import { Prettify } from 'elysia/types'
2-
import { Elysia, ElysiaCustomStatusResponse, t } from '../src'
3-
import { req } from '../test/utils'
4-
import { Tuple } from '../src/types'
1+
import { Elysia } from '../src'
52

6-
type PickOne<T> = T extends any ? T : never
3+
export interface AuthData {
4+
id: number
5+
}
76

8-
new Elysia().get(
9-
'/test',
10-
({ status }) => {
11-
return status(200, { key2: 's', id: 2 })
12-
},
13-
{
14-
response: {
15-
200: t.Union([
16-
t.Object({
17-
key2: t.String(),
18-
id: t.Literal(2)
19-
}),
20-
t.Object({
21-
key: t.Number(),
22-
id: t.Literal(1)
23-
})
24-
])
25-
}
26-
}
27-
)
7+
const app = new Elysia()
8+
.derive(({ request }) => {
9+
const apiKey = request.headers.get('x-api-key')
10+
if (!apiKey) return { auth: null }
11+
12+
return { auth: { id: 1 } satisfies AuthData }
13+
})
14+
.onBeforeHandle(({ auth, set }) => {
15+
console.log(auth?.id)
16+
console.log(set.status)
17+
})
18+
19+
app['~Volatile']

src/types.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,21 +1148,22 @@ type InlineResponse =
11481148
| BunHTMLBundlelike
11491149

11501150
type LastOf<T> =
1151-
UnionToIntersect<T extends any ? () => T : never> extends () => infer R
1152-
? R
1153-
: never;
1151+
UnionToIntersect<T extends any ? () => T : never> extends () => infer R
1152+
? R
1153+
: never
11541154

1155-
type Push<T extends any[], V> = [...T, V];
1155+
type Push<T extends any[], V> = [...T, V]
11561156

1157-
type TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> =
1158-
true extends N
1159-
? []
1160-
: Push<TuplifyUnion<Exclude<T, L>>, L>;
1157+
type TuplifyUnion<
1158+
T,
1159+
L = LastOf<T>,
1160+
N = [T] extends [never] ? true : false
1161+
> = true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>
11611162

1162-
export type Tuple<T, A extends T[] = []> =
1163-
TuplifyUnion<T>['length'] extends A['length']
1164-
? [...A]
1165-
: Tuple<T, [T, ...A]>;
1163+
export type Tuple<
1164+
T,
1165+
A extends T[] = []
1166+
> = TuplifyUnion<T>['length'] extends A['length'] ? [...A] : Tuple<T, [T, ...A]>
11661167

11671168
export type InlineHandler<
11681169
Route extends RouteSchema = {},
@@ -2216,10 +2217,10 @@ type PartialIf<T, Condition extends boolean> = Condition extends true
22162217
// Exclude return error()
22172218
export type ExcludeElysiaResponse<T> = PartialIf<
22182219
Exclude<Awaited<T>, AnyElysiaCustomStatusResponse> extends infer A
2219-
? IsNever<A> extends true
2220+
? IsNever<A & {}> extends true
22202221
? {}
22212222
: // Intersect all union and fallback never to {}
2222-
UnionToIntersect<A & {}>
2223+
A & {}
22232224
: {},
22242225
undefined extends Awaited<T> ? true : false
22252226
>

test/types/index.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2687,3 +2687,39 @@ type a = keyof {}
26872687
{
26882688
new Elysia().get('/file', file('public/takodachi.png'))
26892689
}
2690+
2691+
// derive should add property union correctly
2692+
{
2693+
const app = new Elysia()
2694+
.derive(({ request, status }) => {
2695+
const apiKey = request.headers.get('x-api-key')
2696+
if (!apiKey) return { auth: null }
2697+
2698+
if (Math.random() > 0.5) return status(401)
2699+
2700+
return { auth: { id: 1 } }
2701+
})
2702+
.onBeforeHandle(({ auth }) => {
2703+
expectTypeOf<typeof auth>().toEqualTypeOf<{
2704+
readonly id: 1
2705+
} | null>()
2706+
})
2707+
}
2708+
2709+
// resolve should add property union correctly
2710+
{
2711+
const app = new Elysia()
2712+
.resolve(({ request, status }) => {
2713+
const apiKey = request.headers.get('x-api-key')
2714+
if (!apiKey) return { auth: null }
2715+
2716+
if (Math.random() > 0.5) return status(401)
2717+
2718+
return { auth: { id: 1 } }
2719+
})
2720+
.onBeforeHandle(({ auth }) => {
2721+
expectTypeOf<typeof auth>().toEqualTypeOf<{
2722+
readonly id: 1
2723+
} | null>()
2724+
})
2725+
}

0 commit comments

Comments
 (0)