# Singleton types

A type is a singleton type iff it has exactly one inhabitant.

## Basic

```pyi
from types import UnionType
from typing_extensions import Any, Callable, Literal, Never, TypeAliasType
from ty_extensions import static_assert
from ty_extensions._internal import TypeOf, is_singleton
from enum import Enum

class Answer(Enum):
    NO = 0
    YES = 1

class Single(Enum):
    VALUE = 1

static_assert(is_singleton(None))
static_assert(is_singleton(Literal[True]))
static_assert(is_singleton(Literal[False]))
static_assert(is_singleton(Literal[Answer.YES]))
static_assert(is_singleton(Literal[Answer.NO]))
static_assert(is_singleton(Literal[Single.VALUE]))
static_assert(is_singleton(Single))

def _(answer: Answer) -> None:
    if answer is Answer.NO:
        return
    static_assert(is_singleton(TypeOf[answer]))

def _(answer: Answer & Any) -> None:
    if answer is Answer.NO:
        return
    static_assert(not is_singleton(TypeOf[answer]))

static_assert(is_singleton(type[bool]))

static_assert(not is_singleton(Never))
static_assert(not is_singleton(str))

static_assert(not is_singleton(Literal[345]))
static_assert(not is_singleton(Literal[1, 2]))

static_assert(not is_singleton(tuple[()]))
static_assert(not is_singleton(tuple[None]))
static_assert(not is_singleton(tuple[None, Literal[True]]))

static_assert(not is_singleton(Callable[..., None]))
static_assert(not is_singleton(Callable[[int, str], None]))

static_assert(not is_singleton(TypeAliasType))
static_assert(not is_singleton(UnionType))
static_assert(not is_singleton(TypeOf[list[int]]))
```

## `NoDefault`

### 3.12

```toml
[environment]
python-version = "3.12"
```

```py
from typing_extensions import _NoDefaultType
from ty_extensions import static_assert
from ty_extensions._internal import is_singleton

static_assert(is_singleton(_NoDefaultType))
```

### 3.13

```toml
[environment]
python-version = "3.13"
```

```py
from typing import _NoDefaultType
from ty_extensions import static_assert
from ty_extensions._internal import is_singleton

static_assert(is_singleton(_NoDefaultType))
```

## `builtins.ellipsis`/`types.EllipsisType`

### All Python versions

The type of the builtin symbol `Ellipsis` is the same as the type of an ellipsis literal (`...`).
The type is not actually exposed from the standard library on Python \<3.10, but we still recognize
the type as a singleton on any Python version.

```toml
[environment]
python-version = "3.9"
```

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_singleton

static_assert(is_singleton(Ellipsis.__class__))
```

### Python 3.10+

On Python 3.10+, the standard library exposes the type of `...` as `types.EllipsisType`, and we also
recognize this as a singleton type when it is referenced directly:

```toml
[environment]
python-version = "3.10"
```

```py
import types
from ty_extensions import static_assert
from ty_extensions._internal import is_singleton

static_assert(is_singleton(types.EllipsisType))
```

## `builtins.NotImplemented` / `types.NotImplementedType`

### All Python versions

Just like `Ellipsis`, the type of `NotImplemented` was not exposed on Python \<3.10. However, we
still recognize the type as a singleton in all Python versions.

```toml
[environment]
python-version = "3.9"
```

```py
from ty_extensions import static_assert
from ty_extensions._internal import is_singleton

static_assert(is_singleton(NotImplemented.__class__))
```

### Python 3.10+

On Python 3.10+, the standard library exposes the type of `NotImplemented` as
`types.NotImplementedType`. We also recognize this as a singleton type when it is referenced
directly:

```toml
[environment]
python-version = "3.10"
```

```py
import types
from ty_extensions import static_assert
from ty_extensions._internal import is_singleton

static_assert(is_singleton(types.NotImplementedType))
```

### Callables

We currently treat the type of `types.FunctionType.__get__` as a singleton type that has its own
dedicated variant in the `Type` enum. That variant should be understood as a singleton type, but the
similar variants `Type::BoundMethod` and `Type::MethodWrapperDunderGet` should not be; nor should
`Type::Callable` types.

If we refactor `Type` in the future to get rid of some or all of these `Type` variants, the
assertion that the type of `types.FunctionType.__get__` is a singleton type does not necessarily
have to hold true; it's more of a unit test for our current implementation.

```py
import types
from typing import Callable
from ty_extensions import static_assert
from ty_extensions._internal import TypeOf, is_singleton

class A:
    def method(self): ...

static_assert(is_singleton(TypeOf[types.FunctionType.__get__]))

static_assert(not is_singleton(Callable[[], None]))
static_assert(not is_singleton(TypeOf[A().method]))
static_assert(not is_singleton(TypeOf[A.method.__get__]))
```
