Skip to content

Commit 98e412f

Browse files
committed
🔧 fix: resolve macro with conflict literal value per status
1 parent d416e65 commit 98e412f

File tree

4 files changed

+98
-20
lines changed

4 files changed

+98
-20
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 1.4.25 - 12 Feb 2025
2+
Bug fix:
3+
- resolve macro with conflict literal value per status
4+
15
# 1.4.24 - 11 Feb 2025
26
Feature:
37
- graceful unsigned cookie transition

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "elysia",
33
"description": "Ergonomic Framework for Human",
4-
"version": "1.4.24",
4+
"version": "1.4.25",
55
"author": {
66
"name": "saltyAom",
77
"url": "https://github.com/SaltyAom",

src/types.ts

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -988,27 +988,45 @@ type ExtractOnlyResponseFromMacro<A> =
988988
}
989989
: {}
990990

991-
type ExtractAllResponseFromMacro<A> =
991+
export type ExtractAllResponseFromMacro<A> =
992992
IsNever<A> extends true
993993
? {}
994994
: {
995+
// Merge all status to single object first
995996
return: UnionToIntersect<
996-
A extends ElysiaCustomStatusResponse<
997-
any,
998-
infer Value,
999-
infer Status
1000-
>
1001-
? {
1002-
[status in Status]: IsAny<Value> extends true
1003-
? // @ts-ignore status is always in Status Map
1004-
InvertedStatusMap[Status]
1005-
: Value
1006-
}
1007-
: Exclude<
1008-
A,
1009-
AnyElysiaCustomStatusResponse
1010-
> extends infer A
997+
// Must be using generic to separate literal from Box<T>
998+
A extends ElysiaCustomStatusResponse<any, any, infer Status>
999+
? { [A in Status]: 1 }
1000+
: never
1001+
> extends infer B
1002+
? // Compute each one individually
1003+
{
1004+
// @ts-ignore A is checked in B computation
1005+
[status in keyof B]: Extract<
1006+
A,
1007+
{ code: status }
1008+
>['response']
1009+
} & (Exclude<
1010+
A,
1011+
AnyElysiaCustomStatusResponse
1012+
> extends infer A
10111013
? IsAny<A> extends true
1014+
? {}
1015+
: IsNever<A> extends true
1016+
? {}
1017+
: // FunctionArrayReturnType
1018+
NonNullable<void> extends A
1019+
? {}
1020+
: undefined extends A
1021+
? {}
1022+
: {
1023+
200: A
1024+
}
1025+
: {})
1026+
: Exclude<A, AnyElysiaCustomStatusResponse> extends infer A
1027+
? IsAny<A> extends true
1028+
? {}
1029+
: IsNever<A> extends true
10121030
? {}
10131031
: // FunctionArrayReturnType
10141032
NonNullable<void> extends A
@@ -1018,8 +1036,7 @@ type ExtractAllResponseFromMacro<A> =
10181036
: {
10191037
200: A
10201038
}
1021-
: {}
1022-
>
1039+
: {}
10231040
}
10241041

10251042
// There's only resolve that can add new properties to Context

test/types/lifecycle/soundness.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Cookie, Elysia, ElysiaCustomStatusResponse, t } from '../../../src'
1+
import { Cookie, Elysia, t } from '../../../src'
22
import { expectTypeOf } from 'expect-type'
33
import { Prettify } from '../../../src/types'
44

@@ -2262,3 +2262,60 @@ import { Prettify } from '../../../src/types'
22622262
403: 'Forbidden'
22632263
}>()
22642264
}
2265+
2266+
// Macro with conflict value per status
2267+
{
2268+
const app = new Elysia()
2269+
.macro({
2270+
a: {
2271+
beforeHandle({ status }) {
2272+
if (Math.random()) return status(400, 'a')
2273+
if (Math.random()) return status(401, 'a')
2274+
2275+
return 'a'
2276+
}
2277+
}
2278+
})
2279+
.get('/', () => 'ok', {
2280+
a: true
2281+
})
2282+
2283+
type Route = (typeof app)['~Routes']['get']['response']
2284+
2285+
expectTypeOf<Route>().toEqualTypeOf<{
2286+
200: string
2287+
400: 'a'
2288+
401: 'a'
2289+
}>
2290+
}
2291+
2292+
// Separate Box from literal status-like response in macro
2293+
{
2294+
const app = new Elysia()
2295+
.macro({
2296+
a: {
2297+
beforeHandle({ status }) {
2298+
if (Math.random()) return status(400, 'a')
2299+
if (Math.random()) return status(401, 'a')
2300+
if (Math.random()) return status(401, 'b')
2301+
2302+
if (Math.random())
2303+
// Test status-like response but literal not box
2304+
return { status: 401, response: 'c' } as const
2305+
2306+
return 'a'
2307+
}
2308+
}
2309+
})
2310+
.get('/', () => 'ok', {
2311+
a: true
2312+
})
2313+
2314+
type Route = (typeof app)['~Routes']['get']['response']
2315+
2316+
expectTypeOf<Route>().toEqualTypeOf<{
2317+
200: string | { readonly status: 401; readonly response: 'c' }
2318+
400: 'a'
2319+
401: 'a' | 'b'
2320+
}>
2321+
}

0 commit comments

Comments
 (0)