Skip to content

Commit 2f68e8a

Browse files
committed
Add Exclude and Extract to the TS-utils test
1 parent 42f913f commit 2f68e8a

File tree

1 file changed

+48
-1
lines changed

1 file changed

+48
-1
lines changed

tests/test_ts_utility.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"""
77

88
import textwrap
9-
from typing import Literal, Never, NotRequired, Required, TypedDict
9+
from typing import Literal, Never, NotRequired, Required, TypedDict, Union
1010

1111
import typemap_extensions as typing
1212
from typemap.type_eval import eval_typing
@@ -50,6 +50,7 @@ class TodoTD(TypedDict):
5050

5151
# Omit<T, Keys>
5252
# Constructs a type by picking all properties from T and then removing Keys.
53+
# Note that unlike in TS, our Omit does not depend on Exclude.
5354
type Omit[T, Keys] = typing.NewProtocol[
5455
*[
5556
p
@@ -58,6 +59,27 @@ class TodoTD(TypedDict):
5859
]
5960
]
6061

62+
# Exclude<T, U>
63+
# Constructs a type by excluding from T all union members assignable to U.
64+
type Exclude[T, U] = Union[
65+
*[
66+
x
67+
for x in typing.Iter[typing.FromUnion[T]]
68+
if not typing.IsAssignable[x, U]
69+
]
70+
]
71+
72+
# Extract<T, U>
73+
# Constructs a type by extracting from T all union members assignable to U.
74+
type Extract[T, U] = Union[
75+
*[
76+
x
77+
for x in typing.Iter[typing.FromUnion[T]]
78+
# Just the inverse of Exclude, really
79+
if typing.IsAssignable[x, U]
80+
]
81+
]
82+
6183
# Partial<T>
6284
# Constructs a type with all properties of T set to optional (T | None).
6385
type Partial[T] = typing.NewProtocol[
@@ -156,3 +178,28 @@ def test_td_total_false_inherited():
156178
assert quals["y"] is Never
157179
# z defined in total=True child -> no qual
158180
assert quals["z"] is Never
181+
182+
183+
def test_exclude():
184+
# bool is assignable to int, so it gets excluded too
185+
assert eval_typing(Exclude[str | int | bool, int]) is str
186+
187+
assert eval_typing(
188+
Exclude[Literal["a"] | Literal["b"] | Literal["c"], Literal["a"]]
189+
) == (Literal["b"] | Literal["c"])
190+
191+
assert eval_typing(Exclude[str | int | float, str | int]) is float
192+
193+
194+
def test_extract():
195+
# bool is assignable to int, so it gets extracted
196+
assert eval_typing(Extract[str | int | bool, int]) == (int | bool)
197+
198+
assert (
199+
eval_typing(
200+
Extract[Literal["a"] | Literal["b"] | Literal["c"], Literal["a"]]
201+
)
202+
== Literal["a"]
203+
)
204+
205+
assert eval_typing(Extract[str | int | float, str | int]) == (str | int)

0 commit comments

Comments
 (0)