diff --git a/docs/tutorial/parameter-types/choices.md b/docs/tutorial/parameter-types/choices.md
new file mode 100644
index 0000000000..f7dfe2b74b
--- /dev/null
+++ b/docs/tutorial/parameter-types/choices.md
@@ -0,0 +1,155 @@
+To define a *CLI parameter* that can take a value from a predefined set of values you can use a standard Python
+`enum.Enum` or the
+standard type hint `typing.Literal`
+
+# Enum
+
+```Python hl_lines="1 6 7 8 9 12 13"
+{!../docs_src/parameter_types/choices/tutorial001.py!}
+```
+
+!!! tip
+ Notice that the function parameter `network` will be an `Enum`, not a `str`.
+
+ To get the `str` value in your function's code use `network.value`.
+
+Check it:
+
+
+
+```console
+$ python main.py --help
+
+// Notice the predefined values [simple|conv|lstm]
+Usage: main.py [OPTIONS]
+
+Options:
+ --network [simple|conv|lstm] [default: simple]
+ --help Show this message and exit.
+
+// Try it
+$ python main.py --network conv
+
+Training neural network of type: conv
+
+// Invalid value
+$ python main.py --network capsule
+
+Usage: main.py [OPTIONS]
+Try "main.py --help" for help.
+
+Error: Invalid value for '--network': invalid choice: capsule. (choose from simple, conv, lstm)
+```
+
+
+
+### Case insensitive Enum choices
+
+You can make an `Enum` (choice) *CLI parameter* be case-insensitive with the `case_sensitive` parameter:
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="15"
+ {!> ../docs_src/parameter_types/choices/tutorial002_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="13"
+ {!> ../docs_src/parameter_types/choices/tutorial002.py!}
+ ```
+
+And then the values of the `Enum` will be checked no matter if lower case, upper case, or a mix:
+
+
+
+```console
+// Notice the upper case CONV
+$ python main.py --network CONV
+
+Training neural network of type: conv
+
+// A mix also works
+$ python main.py --network LsTm
+
+Training neural network of type: lstm
+```
+
+
+
+
+## Literal
+
+```Python hl_lines="2 4 7"
+{!../docs_src/parameter_types/choices/tutorial003.py!}
+```
+
+Check it:
+
+
+
+```console
+$ python main.py --help
+
+// Notice the predefined values [simple|conv|lstm]
+Usage: main.py [OPTIONS]
+
+Options:
+ --network [simple|conv|lstm] [default: simple]
+ --help Show this message and exit.
+
+// Try it
+$ python main.py --network conv
+
+Training neural network of type: conv
+
+// Invalid value
+$ python main.py --network capsule
+
+Usage: main.py [OPTIONS]
+Try "main.py --help" for help.
+
+Error: Invalid value for '--network': invalid choice: capsule. (choose from simple, conv, lstm)
+```
+
+
+
+### Case insensitive Literal choices
+
+You can make an `Literal` (choice) *CLI parameter* be case-insensitive with the `case_sensitive` parameter:
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../docs_src/parameter_types/choices/tutorial004_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../docs_src/parameter_types/choices/tutorial004.py!}
+ ```
+
+And then the values of the `Literal` will be checked no matter if lower case, upper case, or a mix:
+
+
+
+```console
+// Notice the upper case CONV
+$ python main.py --network CONV
+
+Training neural network of type: conv
+
+// A mix also works
+$ python main.py --network LsTm
+
+Training neural network of type: lstm
+```
+
+
diff --git a/docs/tutorial/parameter-types/enum.md b/docs/tutorial/parameter-types/enum.md
deleted file mode 100644
index 767c329b27..0000000000
--- a/docs/tutorial/parameter-types/enum.md
+++ /dev/null
@@ -1,77 +0,0 @@
-To define a *CLI parameter* that can take a value from a predefined set of values you can use a standard Python `enum.Enum`:
-
-```Python hl_lines="1 6 7 8 9 12 13"
-{!../docs_src/parameter_types/enum/tutorial001.py!}
-```
-
-!!! tip
- Notice that the function parameter `network` will be an `Enum`, not a `str`.
-
- To get the `str` value in your function's code use `network.value`.
-
-Check it:
-
-
-
-```console
-$ python main.py --help
-
-// Notice the predefined values [simple|conv|lstm]
-Usage: main.py [OPTIONS]
-
-Options:
- --network [simple|conv|lstm] [default: simple]
- --help Show this message and exit.
-
-// Try it
-$ python main.py --network conv
-
-Training neural network of type: conv
-
-// Invalid value
-$ python main.py --network capsule
-
-Usage: main.py [OPTIONS]
-Try "main.py --help" for help.
-
-Error: Invalid value for '--network': invalid choice: capsule. (choose from simple, conv, lstm)
-```
-
-
-
-### Case insensitive Enum choices
-
-You can make an `Enum` (choice) *CLI parameter* be case-insensitive with the `case_sensitive` parameter:
-
-=== "Python 3.6+"
-
- ```Python hl_lines="15"
- {!> ../docs_src/parameter_types/enum/tutorial002_an.py!}
- ```
-
-=== "Python 3.6+ non-Annotated"
-
- !!! tip
- Prefer to use the `Annotated` version if possible.
-
- ```Python hl_lines="13"
- {!> ../docs_src/parameter_types/enum/tutorial002.py!}
- ```
-
-And then the values of the `Enum` will be checked no matter if lower case, upper case, or a mix:
-
-
-
-```console
-// Notice the upper case CONV
-$ python main.py --network CONV
-
-Training neural network of type: conv
-
-// A mix also works
-$ python main.py --network LsTm
-
-Training neural network of type: lstm
-```
-
-
diff --git a/docs_src/parameter_types/enum/__init__.py b/docs_src/parameter_types/choices/__init__.py
similarity index 100%
rename from docs_src/parameter_types/enum/__init__.py
rename to docs_src/parameter_types/choices/__init__.py
diff --git a/docs_src/parameter_types/enum/tutorial001.py b/docs_src/parameter_types/choices/tutorial001.py
similarity index 100%
rename from docs_src/parameter_types/enum/tutorial001.py
rename to docs_src/parameter_types/choices/tutorial001.py
diff --git a/docs_src/parameter_types/enum/tutorial002.py b/docs_src/parameter_types/choices/tutorial002.py
similarity index 100%
rename from docs_src/parameter_types/enum/tutorial002.py
rename to docs_src/parameter_types/choices/tutorial002.py
diff --git a/docs_src/parameter_types/enum/tutorial002_an.py b/docs_src/parameter_types/choices/tutorial002_an.py
similarity index 100%
rename from docs_src/parameter_types/enum/tutorial002_an.py
rename to docs_src/parameter_types/choices/tutorial002_an.py
diff --git a/docs_src/parameter_types/choices/tutorial003.py b/docs_src/parameter_types/choices/tutorial003.py
new file mode 100644
index 0000000000..1532756554
--- /dev/null
+++ b/docs_src/parameter_types/choices/tutorial003.py
@@ -0,0 +1,12 @@
+import typer
+from typing_extensions import Literal
+
+NeuralNetworkType = Literal["simple", "conv", "lstm"]
+
+
+def main(network: NeuralNetworkType = "simple"):
+ print(f"Training neural network of type: {network}")
+
+
+if __name__ == "__main__":
+ typer.run(main)
diff --git a/docs_src/parameter_types/choices/tutorial004.py b/docs_src/parameter_types/choices/tutorial004.py
new file mode 100644
index 0000000000..cb8628e623
--- /dev/null
+++ b/docs_src/parameter_types/choices/tutorial004.py
@@ -0,0 +1,12 @@
+import typer
+from typing_extensions import Literal
+
+NeuralNetworkType = Literal["simple", "conv", "lstm"]
+
+
+def main(network: NeuralNetworkType = typer.Option("simple", case_sensitive=False)):
+ print(f"Training neural network of type: {network}")
+
+
+if __name__ == "__main__":
+ typer.run(main)
diff --git a/docs_src/parameter_types/choices/tutorial004_an.py b/docs_src/parameter_types/choices/tutorial004_an.py
new file mode 100644
index 0000000000..9d4fe56fc2
--- /dev/null
+++ b/docs_src/parameter_types/choices/tutorial004_an.py
@@ -0,0 +1,14 @@
+import typer
+from typing_extensions import Annotated, Literal
+
+NeuralNetworkType = Literal["simple", "conv", "lstm"]
+
+
+def main(
+ network: Annotated[NeuralNetworkType, typer.Option(case_sensitive=False)] = "simple"
+):
+ print(f"Training neural network of type: {network}")
+
+
+if __name__ == "__main__":
+ typer.run(main)
diff --git a/mkdocs.yml b/mkdocs.yml
index 8022a19589..a3cf819af8 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -57,7 +57,7 @@ nav:
- Boolean CLI Options: tutorial/parameter-types/bool.md
- UUID: tutorial/parameter-types/uuid.md
- DateTime: tutorial/parameter-types/datetime.md
- - Enum - Choices: tutorial/parameter-types/enum.md
+ - Choices: tutorial/parameter-types/choices.md
- Path: tutorial/parameter-types/path.md
- File: tutorial/parameter-types/file.md
- Custom Types: tutorial/parameter-types/custom-types.md
diff --git a/tests/test_tutorial/test_parameter_types/test_enum/__init__.py b/tests/test_tutorial/test_parameter_types/test_choices/__init__.py
similarity index 100%
rename from tests/test_tutorial/test_parameter_types/test_enum/__init__.py
rename to tests/test_tutorial/test_parameter_types/test_choices/__init__.py
diff --git a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial001.py b/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial001.py
similarity index 95%
rename from tests/test_tutorial/test_parameter_types/test_enum/test_tutorial001.py
rename to tests/test_tutorial/test_parameter_types/test_choices/test_tutorial001.py
index 584b71a0c7..5b91ff4b8c 100644
--- a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial001.py
+++ b/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial001.py
@@ -4,7 +4,7 @@
import typer
from typer.testing import CliRunner
-from docs_src.parameter_types.enum import tutorial001 as mod
+from docs_src.parameter_types.choices import tutorial001 as mod
runner = CliRunner()
diff --git a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial002.py b/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial002.py
similarity index 92%
rename from tests/test_tutorial/test_parameter_types/test_enum/test_tutorial002.py
rename to tests/test_tutorial/test_parameter_types/test_choices/test_tutorial002.py
index 293a1760bf..7eba5bd215 100644
--- a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial002.py
+++ b/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial002.py
@@ -4,7 +4,7 @@
import typer
from typer.testing import CliRunner
-from docs_src.parameter_types.enum import tutorial002 as mod
+from docs_src.parameter_types.choices import tutorial002 as mod
runner = CliRunner()
diff --git a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial002_an.py b/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial002_an.py
similarity index 91%
rename from tests/test_tutorial/test_parameter_types/test_enum/test_tutorial002_an.py
rename to tests/test_tutorial/test_parameter_types/test_choices/test_tutorial002_an.py
index c60013daa9..51f9b411f3 100644
--- a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial002_an.py
+++ b/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial002_an.py
@@ -4,7 +4,7 @@
import typer
from typer.testing import CliRunner
-from docs_src.parameter_types.enum import tutorial002_an as mod
+from docs_src.parameter_types.choices import tutorial002_an as mod
runner = CliRunner()
diff --git a/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial003.py b/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial003.py
new file mode 100644
index 0000000000..bb55383a7c
--- /dev/null
+++ b/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial003.py
@@ -0,0 +1,50 @@
+import subprocess
+import sys
+
+import typer
+from typer.testing import CliRunner
+
+from docs_src.parameter_types.choices import tutorial003 as mod
+
+runner = CliRunner()
+
+app = typer.Typer()
+app.command()(mod.main)
+
+
+def test_help():
+ result = runner.invoke(app, ["--help"])
+ assert result.exit_code == 0
+ assert "--network" in result.output
+ assert "[simple|conv|lstm]" in result.output
+
+
+def test_main():
+ result = runner.invoke(app, ["--network", "conv"])
+ assert result.exit_code == 0
+ assert "Training neural network of type: conv" in result.output
+
+
+def test_invalid():
+ result = runner.invoke(app, ["--network", "capsule"])
+ assert result.exit_code != 0
+ # TODO: when deprecating Click 7, remove second option
+
+ assert (
+ "Invalid value for '--network': 'capsule' is not one of" in result.output
+ or "Invalid value for '--network': invalid choice: capsule. (choose from"
+ in result.output
+ )
+ assert "simple" in result.output
+ assert "conv" in result.output
+ assert "lstm" in result.output
+
+
+def test_script():
+ result = subprocess.run(
+ [sys.executable, "-m", "coverage", "run", mod.__file__, "--help"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ encoding="utf-8",
+ )
+ assert "Usage" in result.stdout
diff --git a/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial004.py b/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial004.py
new file mode 100644
index 0000000000..5fe0d7cefb
--- /dev/null
+++ b/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial004.py
@@ -0,0 +1,34 @@
+import subprocess
+import sys
+
+import typer
+from typer.testing import CliRunner
+
+from docs_src.parameter_types.choices import tutorial004 as mod
+
+runner = CliRunner()
+
+app = typer.Typer()
+app.command()(mod.main)
+
+
+def test_upper():
+ result = runner.invoke(app, ["--network", "CONV"])
+ assert result.exit_code == 0
+ assert "Training neural network of type: conv" in result.output
+
+
+def test_mix():
+ result = runner.invoke(app, ["--network", "LsTm"])
+ assert result.exit_code == 0
+ assert "Training neural network of type: lstm" in result.output
+
+
+def test_script():
+ result = subprocess.run(
+ [sys.executable, "-m", "coverage", "run", mod.__file__, "--help"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ encoding="utf-8",
+ )
+ assert "Usage" in result.stdout
diff --git a/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial004_an.py b/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial004_an.py
new file mode 100644
index 0000000000..aded51a8ea
--- /dev/null
+++ b/tests/test_tutorial/test_parameter_types/test_choices/test_tutorial004_an.py
@@ -0,0 +1,34 @@
+import subprocess
+import sys
+
+import typer
+from typer.testing import CliRunner
+
+from docs_src.parameter_types.choices import tutorial004_an as mod
+
+runner = CliRunner()
+
+app = typer.Typer()
+app.command()(mod.main)
+
+
+def test_upper():
+ result = runner.invoke(app, ["--network", "CONV"])
+ assert result.exit_code == 0
+ assert "Training neural network of type: conv" in result.output
+
+
+def test_mix():
+ result = runner.invoke(app, ["--network", "LsTm"])
+ assert result.exit_code == 0
+ assert "Training neural network of type: lstm" in result.output
+
+
+def test_script():
+ result = subprocess.run(
+ [sys.executable, "-m", "coverage", "run", mod.__file__, "--help"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ encoding="utf-8",
+ )
+ assert "Usage" in result.stdout
diff --git a/typer/main.py b/typer/main.py
index 9de5f5960d..944c2575d1 100644
--- a/typer/main.py
+++ b/typer/main.py
@@ -13,6 +13,7 @@
import click
+from ._typing import is_literal_type, literal_values
from .completion import get_completion_inspect_parameters
from .core import MarkupMode, TyperArgument, TyperCommand, TyperGroup, TyperOption
from .models import (
@@ -776,6 +777,13 @@ def get_click_type(
[item.value for item in annotation],
case_sensitive=parameter_info.case_sensitive,
)
+
+ if is_literal_type(annotation):
+ return click.Choice(
+ literal_values(annotation),
+ case_sensitive=parameter_info.case_sensitive,
+ )
+
raise RuntimeError(f"Type not yet supported: {annotation}") # pragma no cover