File tree Expand file tree Collapse file tree 8 files changed +144
-14
lines changed
babel-plugin-lingui-macro/src Expand file tree Collapse file tree 8 files changed +144
-14
lines changed Original file line number Diff line number Diff line change @@ -372,5 +372,34 @@ describe("js macro", () => {
372372 } ,
373373 } )
374374 } )
375+
376+ it ( "select without other" , ( ) => {
377+ const exp = parseExpression (
378+ `select(gender, {
379+ male: "he",
380+ female: "she",
381+ })`
382+ )
383+ const tokens = tokenizeChoiceComponent (
384+ ( exp as NodePath < CallExpression > ) . node ,
385+ JsMacroName . select ,
386+ createMacroCtx ( )
387+ )
388+ expect ( tokens ) . toMatchObject ( {
389+ format : "select" ,
390+ name : "gender" ,
391+ options : expect . objectContaining ( {
392+ female : "she" ,
393+ male : "he" ,
394+ offset : undefined ,
395+ other : "" , // <- other should be filled with empty string
396+ } ) ,
397+ type : "arg" ,
398+ value : {
399+ name : "gender" ,
400+ type : "Identifier" ,
401+ } ,
402+ } )
403+ } )
375404 } )
376405} )
Original file line number Diff line number Diff line change @@ -180,6 +180,8 @@ export function tokenizeChoiceComponent(
180180 format : format ,
181181 options : {
182182 offset : undefined ,
183+ /** Default to fill other with empty value for compatibility with ICU spec */
184+ other : "" ,
183185 } ,
184186 }
185187
Original file line number Diff line number Diff line change @@ -322,5 +322,33 @@ describe("jsx macro", () => {
322322 } ,
323323 } )
324324 } )
325+
326+ it ( "Select without other" , ( ) => {
327+ const macro = createMacro ( )
328+ const exp = parseExpression (
329+ `<Select
330+ value={gender}
331+ male="he"
332+ one="heone"
333+ female="she"
334+ />`
335+ )
336+ const tokens = macro . tokenizeNode ( exp )
337+ expect ( tokens [ 0 ] ) . toMatchObject ( {
338+ format : "select" ,
339+ name : "gender" ,
340+ options : {
341+ female : "she" ,
342+ male : "he" ,
343+ offset : undefined ,
344+ other : "" , // <- other should be filled with empty string
345+ } ,
346+ type : "arg" ,
347+ value : {
348+ name : "gender" ,
349+ type : "Identifier" ,
350+ } ,
351+ } )
352+ } )
325353 } )
326354} )
Original file line number Diff line number Diff line change @@ -297,6 +297,8 @@ export class MacroJSX {
297297 value : undefined ,
298298 options : {
299299 offset : undefined ,
300+ /** Default to fill other with empty value for compatibility with ICU spec */
301+ other : "" ,
300302 } ,
301303 }
302304
Original file line number Diff line number Diff line change @@ -266,7 +266,9 @@ expectType<string>(
266266//// Select
267267///////////////////
268268
269- const gender = "male"
269+ type Gender = "male" | "female"
270+ const gender = "male" as Gender // make the type less specific on purpose
271+
270272expectType < 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+
283315expectType < string > (
284316 // @ts -expect-error value could be strings only
285317 select ( 5 , {
Original file line number Diff line number Diff 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/**
Original file line number Diff line number Diff line change @@ -11,7 +11,8 @@ import {
1111import React from "react"
1212import { ph } from "@lingui/core/macro"
1313
14- const gender = "male"
14+ type Gender = "male" | "female"
15+ const gender = "male" as Gender
1516const user = {
1617 name : "John" ,
1718}
@@ -126,8 +127,20 @@ m = (
126127// @ts -expect-error: `value` could be string only
127128m = < Select value = { 5 } other = { "string" } />
128129
129- // @ts -expect-error: `other` required
130- m = < Select value = { "male" } />
130+ // @ts -expect-error: `other` required unless exhaustive
131+ m = < Select value = { gender } />
132+
133+ // @ts -expect-error: `other` required unless exhaustive
134+ m = < Select value = { gender } _male = "..." />
135+
136+ // @ts -expect-error: `other` required unless exhaustive
137+ m = < Select value = { gender } _female = "..." />
138+
139+ // non-exhaustive okay if other is defined
140+ m = < Select value = { gender } _female = "..." other = "..." />
141+
142+ // exhaustive okay without other
143+ m = < Select value = { gender } _male = "..." _female = "..." />
131144
132145// @ts -expect-error: `value` required
133146m = < Select other = { "male" } />
Original file line number Diff line number Diff line change @@ -32,12 +32,25 @@ type PluralChoiceProps = {
3232 [ digit : `_${number } `] : ReactNode
3333} & CommonProps
3434
35- type SelectChoiceProps = {
36- value : string | LabeledExpression < string | number >
35+ type SelectChoiceOptionsExhaustive < T extends string = string > = {
36+ [ key in T as `_${key } `] : ReactNode
37+ }
38+
39+ type SelectChoiceOptionsNonExhaustive < T extends string = string > = {
3740 /** Catch-all option */
3841 other : ReactNode
39- [ option : `_${string } `] : ReactNode
40- } & CommonProps
42+ } & {
43+ [ key in T as `_${key } `] ?: ReactNode
44+ }
45+
46+ type SelectChoiceOptions < T extends string = string > =
47+ | SelectChoiceOptionsExhaustive < T >
48+ | SelectChoiceOptionsNonExhaustive < T >
49+
50+ type SelectChoiceProps < T extends string = string > = {
51+ value : T | LabeledExpression < T >
52+ } & SelectChoiceOptions < T > &
53+ CommonProps
4154
4255/**
4356 * Trans is the basic macro for static messages,
@@ -105,7 +118,9 @@ export const SelectOrdinal: VFC<PluralChoiceProps>
105118 * />
106119 * ```
107120 */
108- export const Select : VFC < SelectChoiceProps >
121+ export const Select : {
122+ < T extends string = string > ( props : SelectChoiceProps < T > ) : React . JSX . Element
123+ }
109124
110125declare function _t ( descriptor : MacroMessageDescriptor ) : string
111126declare function _t (
You can’t perform that action at this time.
0 commit comments