# Use type keyword for defining NewTypes in Non-Generic types

**URL:** <https://discuss.python.org/t/use-type-keyword-for-defining-newtypes-in-non-generic-types/45250>\
**Category:** Ideas\
**Tags:** typing\
**Created:** [February 7, 2024, 9:37am UTC](https://discuss.python.org/t/use-type-keyword-for-defining-newtypes-in-non-generic-types/45250 "2024-02-07T09:37:03Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![PabloRuizCuevas](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pabloruizcuevas/32/17298_2.png) [@PabloRuizCuevas](https://discuss.python.org/u/PabloRuizCuevas)\
**Post date:** [February 7, 2024, 9:37am UTC](https://discuss.python.org/t/use-type-keyword-for-defining-newtypes-in-non-generic-types/45250/1 "2024-02-07T09:37:03Z")

</div>

Now type aliases for Non-generic types are almost useless, like the one showed in the [PEP 484](https://peps.python.org/pep-0484/#type-aliases)

```python
Url = str
def retry(url: Url, retry_count: int) -> None: ...

```

With the modern syntax, we would have:

```python
type Url = str
def retry(url: Url, retry_count: int) -> None: ...

```

Which won’t do anything in static analysis:

```python
test: str = 'not_an_url'
test1 = retry(test) # Doesn't give a static warning

test = 'not_an_url'
test2 = retry(test) # Doesn't give a warning, but may be nice based on --strict

test: Url = 'not_an_url'
test3 = retry(test) # Doesn't give a static warning (It shouldn't)

```

So in my opinion we are better off just omitting the alias, and ensure that the variable name is descriptive. Or better use typing.NewType.

```python
def retry(url: str, retry_count: int) -> None: ... # option 1

Url = NewType("Url", str)
def retry(url: Url, retry_count: int) -> None: ... # option 2

```

Given that I can’t see any use-case of an alias in a Non-generic type, please tell me if I’m missing something. My proposal would be, using the keyword ` type` for defining Newtypes in Non generics:

```python
type Url = str # interpret this as NewType , it can be subclassed
type UrlList = list[Url] # interpret this as Alias (TypeAliasType), it can't be subclassed

```

Considering that one can be sub-classed and the other not:

```python
class Url(str): pass # This is valid
class UrlList(list[Url]): pass # This is not valid

```

This behavior will be more in line with what I would expect when using the word “type”. And also gives a real usage to the keyword `type` with non-generic classes.

PD: This topic was already discussed here [#45186](https://discuss.python.org/t/static-enforced-non-generic-type-alias/45186), where I questioned this behavior, before i figured out how and why it works like that. This post intends to be a proposal after having a slightly deeper understanding on the topic. In any case if is too similar for the rules of the forum, feel free to close it or tell me to do so.

---

<div class="post-metadata">

**Author:** ![srittau](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/srittau/32/237_2.png) [@srittau](https://discuss.python.org/u/srittau)\
**Post date:** [February 7, 2024, 11:20am UTC](https://discuss.python.org/t/use-type-keyword-for-defining-newtypes-in-non-generic-types/45250/3 "2024-02-07T11:20:53Z")

</div>

> [@PabloRuizCuevas](#):
>
> Now type aliases for Non-generic types are almost useless,

They are very useful, as the ~1200 type aliases – of which only a small number is generic – in typeshed show.

---

<div class="post-metadata">

**Author:** ![MegaIng](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/megaing/32/16162_2.png) [@MegaIng](https://discuss.python.org/u/MegaIng)\
**Post date:** [February 7, 2024, 12:08pm UTC](https://discuss.python.org/t/use-type-keyword-for-defining-newtypes-in-non-generic-types/45250/4 "2024-02-07T12:08:27Z")

</div>

> [@PabloRuizCuevas](#):
>
> Considering that one can be sub-classed and the other not:
> 
> ```python
> class Url(str): pass # This is valid
> class UrlList(list[Url]): pass # This is not valid
> 
> ```

Incorrect, those are both valid.

---

<div class="post-metadata">

**Author:** ![AndersMunch](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/andersmunch/32/12823_2.png) [@AndersMunch](https://discuss.python.org/u/AndersMunch)\
**Post date:** [February 7, 2024, 12:43pm UTC](https://discuss.python.org/t/use-type-keyword-for-defining-newtypes-in-non-generic-types/45250/5 "2024-02-07T12:43:12Z")

</div>

If I understand you correctly, you are asking for a type alias facility that works by _name equivalence_, unlike assignment aliases which work by _structural equivalence_. I suggest you read up on those concepts. Wikipedia seems to be using different words for it: [Nominal type system - Wikipedia](https://en.wikipedia.org/wiki/Nominal_type_system) and [Structural type system - Wikipedia](https://en.wikipedia.org/wiki/Structural_type_system) - maybe terminology has changed over time.

It’s an age old discussion which is better. I think the world mostly settled on structural equivalence. The problem with name equivalence is that you keep ending up in situations where you need an `Url`, but all you have is a `str`, and then you end up casting all the time.

---

<div class="post-metadata">

**Author:** ![PabloRuizCuevas](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pabloruizcuevas/32/17298_2.png) [@PabloRuizCuevas](https://discuss.python.org/u/PabloRuizCuevas)\
**Post date:** [February 7, 2024, 1:09pm UTC](https://discuss.python.org/t/use-type-keyword-for-defining-newtypes-in-non-generic-types/45250/6 "2024-02-07T13:09:03Z")

</div>

Ok, thanks everyone, now I see more things that I though were not possible:

```python
class UrlList(list[str]): pass # this is indeed valid.

```

Also the difference between Structural and nominal types systems is very illustrative, as well as the observation the that usage of NewType may force casting as well.

I guess i could close this Idea, because even if we would want (that won’t be the case) is actually impossible to implement, cause everything can be sub-classed.
