/
switch-expression.test.ts
153 lines (137 loc) · 4.35 KB
/
switch-expression.test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import { expectType } from "tsd"
import { switchExpression } from "~/switch-expression"
describe("switchExpression", () => {
describe("Declaration type is appropriate", () => {
it("appropriate case type", () => {
const status = "value" as "value" | "guard" | "validate" | "remain"
const result = switchExpression(status)
.case("value", "valueResult" as const)
.case((value): value is "guard" => {
// Exclude 'value' literal
expectType<"guard" | "validate" | "remain">(value)
return true
}, "guardResult" as const)
.case((value) => {
// Exclude 'guard' literal
expectType<"validate" | "remain">(value)
return true
}, "ngResult" as const)
.case((value) => {
// Not Exclude 'validate" | 'remain' literal
expectType<"validate" | "remain">(value)
return true
}, "skipResult" as const)
.default("defaultResult" as const)
expectType<
| "valueResult"
| "guardResult"
| "ngResult"
| "skipResult"
| "defaultResult"
>(result)
})
it("appropriate value type", () => {
const status = "value" as "value" | "guard" | "validate" | "remain"
const result = switchExpression(status)
.case("value", (value) => {
// constrict as value
expectType<"value">(value)
return "valueResult" as const
})
.case(
(_value): _value is "guard" => true,
(value) => {
// constrict as guarded
expectType<"guard">(value)
return "guardResult" as const
}
)
.case(
(_value) => true,
(value) => {
// not constrict
expectType<"validate" | "remain">(value)
return "ngResult" as const
}
)
.default("defaultResult" as const)
expectType<"valueResult" | "guardResult" | "ngResult" | "defaultResult">(
result
)
})
it("Default value is required when all patterns are not type guarded", () => {
const status = "1" as "1" | "2"
switchExpression(status)
.case("1", "1")
// @ts-expect-error -- for test
.default()
})
it("When all patterns can be type guarded, the default value is forbidden.", () => {
const status = "1" as "1" | "2"
switchExpression(status)
.case("1", "1")
.case("2", "2")
// @ts-expect-error -- for test
.default("defaultValue")
})
})
describe("Actual behavior for value pattern", () => {
const callExpression = (status: "ok" | "ng"): "okResult" | "ngResult" => {
return switchExpression(status)
.case("ok", "okResult" as const)
.case("ng", "ngResult" as const)
.default()
}
it("ok", () => {
expect(callExpression("ok")).toBe("okResult")
})
it("ng", () => {
expect(callExpression("ng")).toBe("ngResult")
})
})
describe("Actual behavior for type guard pattern", () => {
const callExpression = (status: "ok" | "ng"): "okResult" | "ngResult" => {
return switchExpression(status)
.case((value): value is "ok" => value === "ok", "okResult" as const)
.case((_value): _value is "ng" => true, "ngResult" as const)
.default()
}
it("ok", () => {
expect(callExpression("ok")).toBe("okResult")
})
it("ng", () => {
expect(callExpression("ng")).toBe("ngResult")
})
})
describe("Actual behavior for validate & resolver pattern", () => {
const callExpression = (
status: "ok" | "ng" | "unchecked"
): "okResult" | "ngResult" | "defaultValue" => {
return switchExpression(status)
.case(
(value) => value === "ok",
(value) => {
expect(value).toBe(status)
return "okResult" as const
}
)
.case(
(value) => value === "ng",
(value) => {
expect(value).toBe(status)
return "ngResult" as const
}
)
.default("defaultValue" as const)
}
it("ok", () => {
expect(callExpression("ok")).toBe("okResult")
})
it("ng", () => {
expect(callExpression("ng")).toBe("ngResult")
})
it("unchecked", () => {
expect(callExpression("unchecked")).toBe("defaultValue")
})
})
})