Skip to content

Commit 1cb6521

Browse files
committed
fix intersection with not type
1 parent 7b12f1a commit 1cb6521

File tree

3 files changed

+33
-19
lines changed

3 files changed

+33
-19
lines changed

packages/predicate/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
An eDSL to write typed predicates
66

77
```ts
8-
import { ps } from "@sthir/predicate"
8+
import { p } from "@sthir/predicate"
99

1010
declare let xs:
1111
(undefined | { a: string | number } | { b: string })[]
@@ -35,7 +35,7 @@ xs
3535
```
3636

3737
```ts
38-
import { pa, ps } from "@sthir/predicate"
38+
import { pa, p } from "@sthir/predicate"
3939

4040
declare let foo:
4141
| { bar: { type: "x" }
@@ -56,7 +56,7 @@ if (foo.bar.type === "x") {
5656

5757
// With @sthir/predicate ...
5858

59-
if (pa(foo, ps(".bar.type ===", "x"))) {
59+
if (pa(foo, p(".bar.type ===", "x"))) {
6060
foo.x
6161
}
6262
```
@@ -108,7 +108,7 @@ export const pa:
108108
### Supported comparators
109109
110110
- `===`
111-
- `!==` (does not work in [some cases](https://github.com/devanshj/sthir/blob/8a195542cf2b204e8d30fa63fb2abcc5571bf800/packages/predicate/tests/types.twoslash-test.ts#L71-L78) because of [#47283](https://github.com/microsoft/TypeScript/issues/47283))
111+
- `!==`
112112

113113
### Future
114114

packages/predicate/src/types.ts

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ namespace A {
218218
declare const $$not: unique symbol
219219
export type Not<T> = { [$$not]: T }
220220

221-
export type NotAwareIntersect<A, B> =
221+
export type NotAwareIntersect<A, B, A_ = A> =
222222
B extends Not<infer NotB>
223223
? A extends object
224224
? A.Get<U.ToIntersection<
@@ -228,8 +228,11 @@ namespace A {
228228
? O.Normalize<
229229
& A
230230
& O.Normalize<{
231-
[K in Extract<keyof NotB, keyof A>]:
232-
NotAwareIntersect<A[K], A.Not<NotB[K]>>
231+
[K in keyof NotB]:
232+
NotAwareIntersect<
233+
A_ extends unknown ? A.Get<A_, K> : never,
234+
A.Not<NotB[K]>
235+
>
233236
}>
234237
>
235238
: A
@@ -239,7 +242,6 @@ namespace A {
239242
: A extends NotB
240243
? never
241244
: A
242-
243245
: A & B
244246

245247
A.test(A.areEqual
@@ -254,19 +256,26 @@ namespace A {
254256
>()
255257
)
256258

259+
A.test(A.areEqual
260+
< NotAwareIntersect<{ a: string | undefined } | { b: string }, A.Not<{ a: undefined }>>
261+
, | ({ a: string | undefined } & { a: string })
262+
| ({ b: string } & { a: string })
263+
>()
264+
)
265+
257266
A.test(A.areEqual
258267
< NotAwareIntersect<
259268
{ x: "A" } | { y: "X" | "Z" } | "B" | "C"
260269
, A.Not<{ x: "A" } | { y: "X" } | "B">
261270
>
262-
, | ({ y: "X" | "Z" } & { y: "Z" })
271+
, | ({ y: "X" | "Z" } & { x: undefined } & { y: "Z" | undefined })
263272
| "C"
264273
>()
265274
)
266275

267276
A.test(A.areEqual
268277
< NotAwareIntersect<{ x: "A" | "Z" } | "B" | "C", A.Not<{ x: "A" } | "B">>
269-
, | ({ x: "A" | "Z" } & { x: "Z" })
278+
, | ({ x: "A" | "Z" } & { x: "Z" | undefined })
270279
| "C"
271280
>()
272281
)
@@ -280,17 +289,21 @@ namespace A {
280289
| "B"
281290
| "C"
282291
, A.Not<
283-
| { x: "A", y: { x: "B" } }
292+
| { y: { x: "B" } }
284293
| { z: "T" | "U" }
285294
| "B"
286295
>
287296
>
288297
, | ( { x: "A"
289298
, y: { x: "B" | "Z" }
290299
}
291-
& { x: never
292-
, y: { x: "B" | "Z" } & { x: "Z" }
300+
& { y:
301+
| ( { x: "B" | "Z" }
302+
& { x: "Z" | undefined }
303+
)
304+
| undefined;
293305
}
306+
& { z: undefined }
294307
)
295308
| "C"
296309
>()
@@ -302,14 +315,19 @@ namespace A {
302315
>()
303316
)
304317

318+
A.test(A.areEqual
319+
< NotAwareIntersect<{ a?: string }, A.Not<{ a: A.Falsy }>>
320+
, { a?: string } & { a: string }
321+
>()
322+
)
323+
305324
export type Falsy =
306325
false | undefined | null | 0 | 0n | ""
307326

308327
export type Get<T, P> =
309328
B.Not<A.DoesExtend<P, unknown[]>> extends true ? Get<T, [P]> :
310329
P extends [] ? T :
311330
P extends [infer Ph] ?
312-
object extends T ? unknown :
313331
Ph extends keyof T ? T[Ph] :
314332
T extends null ? null :
315333
T extends undefined ? undefined :
@@ -370,7 +388,4 @@ namespace O {
370388
export type Normalize<T> =
371389
{} extends T ? unknown :
372390
T[keyof T] extends never ? never : T
373-
374-
export type Key<T> =
375-
object extends T ? keyof any : keyof T
376391
}

packages/predicate/tests/types.twoslash-test.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ test("index typeof !==", () => {
7272
let x = {} as { a: string | number | undefined } | { b: string }
7373

7474
if (pa(x, p(".a typeof !==", "undefined"))) {
75-
// @ts-expect-error https://github.com/microsoft/TypeScript/issues/47283
7675
expectAreTypesEqual<typeof x.a, string | number>().toBe(true)
7776
}
7877
})
@@ -117,4 +116,4 @@ const expectAreTypesEqual =
117116
? true
118117
: false
119118
) => {}
120-
})
119+
})

0 commit comments

Comments
 (0)