Skip to content

Commit e20dc0d

Browse files
feat(macro): make select macro choices strictly typed
1 parent d77d6c1 commit e20dc0d

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

packages/core/macro/__typetests__/index.test-d.tsx

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,9 @@ expectType<string>(
266266
//// Select
267267
///////////////////
268268

269-
const gender = "male"
269+
type Gender = "male" | "female" | "other"
270+
const gender = "male" as Gender // make the type less specific on purpose
271+
270272
expectType<string>(
271273
select(gender, {
272274
// todo: here is inconsistency between jsx macro and js.
@@ -280,6 +282,36 @@ expectType<string>(
280282
})
281283
)
282284

285+
expectType<string>(
286+
// @ts-expect-error: missing required property and other is not supplied
287+
select(gender, {
288+
male: "he",
289+
})
290+
)
291+
292+
expectType<string>(
293+
// missing required property is okay, if other is supplied as fallback
294+
select(gender, {
295+
male: "he",
296+
other: "they",
297+
})
298+
)
299+
300+
expectType<string>(
301+
select(gender, {
302+
// @ts-expect-error extra properties are not allowed
303+
incorrect: "",
304+
})
305+
)
306+
307+
expectType<string>(
308+
select(gender, {
309+
// @ts-expect-error extra properties are not allowed even with other fallback
310+
incorrect: "",
311+
other: "they",
312+
})
313+
)
314+
283315
expectType<string>(
284316
// @ts-expect-error value could be strings only
285317
select(5, {

packages/core/macro/index.d.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,21 @@ export function selectOrdinal(
154154
options: ChoiceOptions
155155
): string
156156

157-
type SelectOptions = {
157+
type SelectOptionsExhaustive<T extends string = string> = {
158+
[key in T]: string
159+
}
160+
161+
type SelectOptionsNonExhaustive<T extends string = string> = {
158162
/** Catch-all option */
159163
other: string
160-
[matches: string]: string
164+
} & {
165+
[key in T]?: string
161166
}
162167

168+
type SelectOptions<T extends string = string> =
169+
| SelectOptionsExhaustive<T>
170+
| SelectOptionsNonExhaustive<T>
171+
163172
/**
164173
* Selects a translation based on a value
165174
*
@@ -180,9 +189,9 @@ type SelectOptions = {
180189
* @param value The key of choices to use
181190
* @param choices
182191
*/
183-
export function select(
184-
value: string | LabeledExpression<string>,
185-
choices: SelectOptions
192+
export function select<T extends string = string>(
193+
value: T | LabeledExpression<T>,
194+
choices: SelectOptions<T>
186195
): string
187196

188197
/**

0 commit comments

Comments
 (0)