Skip to content

Commit 9969aed

Browse files
feat: improve type inference for template literals .each syntax
1 parent 5daab90 commit 9969aed

File tree

3 files changed

+31
-16
lines changed

3 files changed

+31
-16
lines changed

docs/GlobalAPI.md

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,7 +1050,7 @@ test.each(table)('table as a variable example', (a, b, expected, extra) => {
10501050

10511051
#### Template literal
10521052

1053-
If all values are of the same type, the template literal API will type the arguments correctly:
1053+
If all input values are of the same type, the template literal API will type the arguments correctly:
10541054

10551055
```ts
10561056
import {test} from '@jest/globals';
@@ -1060,12 +1060,27 @@ test.each`
10601060
${1} | ${2} | ${3}
10611061
${3} | ${4} | ${7}
10621062
${5} | ${6} | ${11}
1063-
`('template literal example', ({a, b, expected}) => {
1064-
// all arguments are of type `number`
1063+
`('template literal example same type', ({a, b, expected}) => {
1064+
// all arguments are of type `number` because all inputs (a, b, expected) are of type `number`
10651065
});
10661066
```
10671067

1068-
Otherwise it will require a generic type argument:
1068+
If the inputs have different types, the arguments will be typed as a union of all the input types (ie type of the variables inside the template literal):
1069+
1070+
```ts
1071+
import {test} from '@jest/globals';
1072+
1073+
test.each`
1074+
a | b | expected
1075+
${1} | ${2} | ${'three'}
1076+
${3} | ${4} | ${'seven'}
1077+
${5} | ${6} | ${'eleven'}
1078+
`('template literal example different types', ({a, b, expected}) => {
1079+
// all arguments are of type `number | string` because some inputs (a, b) are of type `number` and some others (expected) are of type `string`
1080+
});
1081+
```
1082+
1083+
Otherwise, if you want each argument to have the right type, you have to explicitly provide the generic type argument:
10691084

10701085
```ts
10711086
import {test} from '@jest/globals';
@@ -1076,6 +1091,6 @@ test.each<{a: number; b: number; expected: string; extra?: boolean}>`
10761091
${3} | ${4} | ${'seven'} | ${false}
10771092
${5} | ${6} | ${'eleven'}
10781093
`('template literal example', ({a, b, expected, extra}) => {
1079-
// without the generic argument in this case types would default to `unknown`
1094+
// all arguments are typed as expected, e.g. `a: number`, `expected: string`, `extra: boolean | undefined`
10801095
});
10811096
```

packages/jest-types/__typetests__/each.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,8 @@ expectType<void>(
217217
${'a'} | ${true}
218218
${'b'} | ${false}
219219
`('some test', ({item, expected}) => {
220-
expectType<unknown>(item);
221-
expectType<unknown>(expected);
220+
expectType<string | boolean>(item);
221+
expectType<string | boolean>(expected);
222222
}),
223223
);
224224
expectType<void>(
@@ -257,8 +257,8 @@ expectType<void>(
257257
`(
258258
'some test',
259259
({item, expected}) => {
260-
expectType<unknown>(item);
261-
expectType<unknown>(expected);
260+
expectType<string | boolean>(item);
261+
expectType<string | boolean>(expected);
262262
},
263263
1000,
264264
),
@@ -393,8 +393,8 @@ expectType<void>(
393393
${'a'} | ${true}
394394
${'b'} | ${false}
395395
`('some test', async ({item, expected}) => {
396-
expectType<unknown>(item);
397-
expectType<unknown>(expected);
396+
expectType<string | boolean>(item);
397+
expectType<string | boolean>(expected);
398398
}),
399399
);
400400
expectType<void>(
@@ -432,8 +432,8 @@ expectType<void>(
432432
`(
433433
'some test',
434434
({item, expected}) => {
435-
expectType<unknown>(item);
436-
expectType<unknown>(expected);
435+
expectType<string | boolean>(item);
436+
expectType<string | boolean>(expected);
437437
},
438438
1000,
439439
),

packages/jest-types/src/Global.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,12 @@ interface Each<EachFn extends TestFn | BlockFn> {
9393
) => void;
9494

9595
// when the table is a template literal
96-
<T = unknown>(
96+
<T extends Array<unknown>>(
9797
strings: TemplateStringsArray,
98-
...expressions: Array<T>
98+
...expressions: T
9999
): (
100100
name: string | NameLike,
101-
fn: (arg: Record<string, T>, done: DoneFn) => ReturnType<EachFn>,
101+
fn: (arg: Record<string, T[number]>, done: DoneFn) => ReturnType<EachFn>,
102102
timeout?: number,
103103
) => void;
104104

0 commit comments

Comments
 (0)