Skip to content

Commit 8b928dd

Browse files
committed
fix(P.nonNullable): add unit tests
1 parent e1272af commit 8b928dd

File tree

3 files changed

+60
-35
lines changed

3 files changed

+60
-35
lines changed

src/types/ExtractPreciseValue.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export type ExtractPreciseValue<a, b> = b extends Override<infer b1>
4141
? never
4242
: // An empty object `{}` in a pattern means
4343
// that this key must be non-nullable.
44-
// If find a key in `b` that doesn't exist in `a`
44+
// If we find a key in `b` that doesn't exist in `a`
4545
// and that contains `{}`, then the pattern does not match.
4646
Contains<Omit<b, keyof a>, {}> extends true
4747
? never

tests/extract-precise-value.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { ExtractPreciseValue } from '../src/types/ExtractPreciseValue';
2+
import { InvertPattern } from '../src/types/InvertPattern';
3+
import { NonNullablePattern } from '../src/types/Pattern';
24
import { Expect, Equal } from '../src/types/helpers';
35
import { AsyncResult, Event, Option, State } from './types-catalog/utils';
46

@@ -292,6 +294,55 @@ describe('ExtractPreciseValue', () => {
292294
});
293295
});
294296

297+
describe('non-nullable patterns', () => {
298+
type nonNullable = InvertPattern<NonNullablePattern, unknown>;
299+
300+
it('should exclude objects if the absent', () => {
301+
type res1 = ExtractPreciseValue<{ a: string }, { b: nonNullable }>;
302+
type test1 = Expect<Equal<res1, never>>;
303+
304+
type res2 = ExtractPreciseValue<
305+
{ a: string } | { b: number },
306+
{ b: nonNullable }
307+
>;
308+
type test2 = Expect<Equal<res2, { b: number }>>;
309+
310+
type res3 = ExtractPreciseValue<
311+
{ a: string } | { b: number } | { b: string; c: boolean },
312+
{ b: nonNullable }
313+
>;
314+
type test3 = Expect<
315+
Equal<res3, { b: number } | { b: string; c: boolean }>
316+
>;
317+
});
318+
319+
it('should keep empty objects if they come from the input type', () => {
320+
type res1 = ExtractPreciseValue<
321+
{ a: string } | { b: {} },
322+
{ b: nonNullable }
323+
>;
324+
type test1 = Expect<Equal<res1, { b: {} }>>;
325+
});
326+
327+
it('should exclude objects even if the non-nullable key is deeply nested', () => {
328+
type res1 = ExtractPreciseValue<{ a: number }, { b: { c: nonNullable } }>;
329+
type test1 = Expect<Equal<res1, never>>;
330+
331+
type res2 = ExtractPreciseValue<
332+
| { nested: { a: string } }
333+
| { nested: { b: number } }
334+
| { nested: { b: string; c: boolean } },
335+
{ nested: { b: nonNullable } }
336+
>;
337+
type test2 = Expect<
338+
Equal<
339+
res2,
340+
{ nested: { b: number } } | { nested: { b: string; c: boolean } }
341+
>
342+
>;
343+
});
344+
});
345+
295346
describe('Branded strings', () => {
296347
it('Type narrowing should correctly work on branded strings', () => {
297348
// Branded strings is a commonly used way of implementing

tests/wildcards.test.ts

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,7 @@ describe('wildcards', () => {
8484
type Input =
8585
| {
8686
__typename: 'ValidationRejection';
87-
fields: {
88-
__typename: 'ValidationFieldError';
89-
path: string[];
90-
message: string;
91-
}[];
87+
fields: string[];
9288
}
9389
| {
9490
__typename: 'ValidationRejection';
@@ -106,38 +102,16 @@ describe('wildcards', () => {
106102
.with(
107103
{ __typename: 'ValidationRejection', fields: P.nonNullable },
108104
({ fields }) => {
109-
type t = Expect<
110-
Equal<
111-
typeof fields,
112-
{
113-
__typename: 'ValidationFieldError';
114-
path: string[];
115-
message: string;
116-
}[]
117-
>
118-
>;
105+
type t = Expect<Equal<typeof fields, string[]>>;
106+
return 'matched';
119107
}
120108
)
121-
.otherwise(() => {});
109+
.otherwise(() => 'did not match');
122110

123-
const fn2 = (data: Input) =>
124-
match(data)
125-
.with(
126-
{ __typename: 'ValidationRejection', fields: P.not(P.nullish) },
127-
({ fields }) => {
128-
type t = Expect<
129-
Equal<
130-
typeof fields,
131-
{
132-
__typename: 'ValidationFieldError';
133-
path: string[];
134-
message: string;
135-
}[]
136-
>
137-
>;
138-
}
139-
)
140-
.otherwise(() => {});
111+
expect(fn({ __typename: 'ValidationRejection' })).toBe('did not match');
112+
expect(fn({ __typename: 'ValidationRejection', fields: [] })).toBe(
113+
'matched'
114+
);
141115
});
142116
});
143117

0 commit comments

Comments
 (0)