<h3 dir="auto">Describe the issue:</h3>
<p dir="auto">numpy 1.20 <a href="https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations" rel="nofollow">encouraged</a> specifying plain <code class="notranslate">bool</code> as a dtype as an equivalent to <code class="notranslate">np.bool_</code>, but these aliases don't behave the same as the explicit numpy versions. mypy infers the dtype as "Any" instead. See the example below, where I expected both lines to output the same type.</p>
<h3 dir="auto">Reproduce the code example:</h3>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import numpy as np

def what_the() -&gt; None:
    reveal_type(np.arange(10, dtype=bool))
    reveal_type(np.arange(10, dtype=np.bool_))"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">numpy</span> <span class="pl-k">as</span> <span class="pl-s1">np</span>

<span class="pl-k">def</span> <span class="pl-en">what_the</span>() <span class="pl-c1">-&gt;</span> <span class="pl-c1">None</span>:
    <span class="pl-en">reveal_type</span>(<span class="pl-s1">np</span>.<span class="pl-en">arange</span>(<span class="pl-c1">10</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s1">bool</span>))
    <span class="pl-en">reveal_type</span>(<span class="pl-s1">np</span>.<span class="pl-en">arange</span>(<span class="pl-c1">10</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s1">np</span>.<span class="pl-s1">bool_</span>))</pre></div>
<h3 dir="auto">Error message:</h3>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="No error, but output from mypy 0.961:

show_type2.py:4: note: Revealed type is &quot;numpy.ndarray[Any, numpy.dtype[Any]]&quot;
show_type2.py:5: note: Revealed type is &quot;numpy.ndarray[Any, numpy.dtype[numpy.bool_]]&quot;"><pre class="notranslate">No error, but output from mypy 0.961:

show_type2.py:4: note: Revealed <span class="pl-c1">type</span> is <span class="pl-s"><span class="pl-pds">"</span>numpy.ndarray[Any, numpy.dtype[Any]]<span class="pl-pds">"</span></span>
show_type2.py:5: note: Revealed <span class="pl-c1">type</span> is <span class="pl-s"><span class="pl-pds">"</span>numpy.ndarray[Any, numpy.dtype[numpy.bool_]]<span class="pl-pds">"</span></span></pre></div>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="

### NumPy/Python version information:

1.23.0 3.10.5 (main, Jun 11 2022, 16:53:24) [GCC 9.4.0]"><pre class="notranslate"><code class="notranslate">

### NumPy/Python version information:

1.23.0 3.10.5 (main, Jun 11 2022, 16:53:24) [GCC 9.4.0]
</code></pre></div>
<p dir="auto">Back in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="737189661" data-permission-text="Title is private" data-url="https://github.com/numpy/numpy/issues/17719" data-hovercard-type="pull_request" data-hovercard-url="/numpy/numpy/pull/17719/hovercard" href="https://github.com/numpy/numpy/pull/17719">#17719</a> the first steps were taken into introducing static typing support for array dtypes.</p>
<p dir="auto">Since the dtype has a substantial effect on the semantics of an array, there is a lot of type-safety<br>
to be gained if the various function-annotations in numpy can actually utilize this information.<br>
Examples of this would be the rejection of string-arrays for arithmetic operations, or inferring the<br>
output dtype of mixed float/integer operations.</p>
<h2 dir="auto">The Plan</h2>
<p dir="auto">With this in mind I'd ideally like to implement some basic dtype support throughout the main numpy<br>
namespace (xref <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="635526762" data-permission-text="Title is private" data-url="https://github.com/numpy/numpy/issues/16546" data-hovercard-type="issue" data-hovercard-url="/numpy/numpy/issues/16546/hovercard" href="https://github.com/numpy/numpy/issues/16546">#16546</a>) before the release of 1.22.</p>
<p dir="auto">Now, what does "basic" mean in this context? Namely, any array-/dtype-like that can be parametrized<br>
w.r.t. <code class="notranslate">np.generic</code>. Notably this excludes builtin scalar types and character codes (literal strings), as the<br>
only way of implementing the latter two is via excessive use of overloads.</p>
<p dir="auto">With this in mind, I realistically only expect dtype-support for builtin scalar types (<em>e.g.</em> <code class="notranslate">func(..., dtype=float)</code>)<br>
to-be added with the help of a mypy plugin, <em>e.g.</em> via injecting a type-check-only method into the likes of<br>
<code class="notranslate">builtins.int</code> that holds some sort of explicit reference to <code class="notranslate">np.int_</code>.</p>
<h2 dir="auto">Examples</h2>
<p dir="auto">Two examples wherein the dtype can be automatically inferred:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from typing import TYPE_CHECKING
import numpy as np

AR_1 = np.array(np.float64(1))
AR_2 = np.array(1, dtype=np.float64)

if TYPE_CHECKING:
    reveal_type(AR_1)  # note: Revealed type is &quot;numpy.ndarray[Any, numpy.dtype[numpy.floating*[numpy.typing._64Bit*]]]&quot;
    reveal_type(AR_2)  # note: Revealed type is &quot;numpy.ndarray[Any, numpy.dtype[numpy.floating*[numpy.typing._64Bit*]]]&quot;"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">typing</span> <span class="pl-k">import</span> <span class="pl-v">TYPE_CHECKING</span>
<span class="pl-k">import</span> <span class="pl-s1">numpy</span> <span class="pl-k">as</span> <span class="pl-s1">np</span>

<span class="pl-v">AR_1</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">array</span>(<span class="pl-s1">np</span>.<span class="pl-en">float64</span>(<span class="pl-c1">1</span>))
<span class="pl-v">AR_2</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">array</span>(<span class="pl-c1">1</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s1">np</span>.<span class="pl-s1">float64</span>)

<span class="pl-k">if</span> <span class="pl-v">TYPE_CHECKING</span>:
    <span class="pl-en">reveal_type</span>(<span class="pl-v">AR_1</span>)  <span class="pl-c"># note: Revealed type is "numpy.ndarray[Any, numpy.dtype[numpy.floating*[numpy.typing._64Bit*]]]"</span>
    <span class="pl-en">reveal_type</span>(<span class="pl-v">AR_2</span>)  <span class="pl-c"># note: Revealed type is "numpy.ndarray[Any, numpy.dtype[numpy.floating*[numpy.typing._64Bit*]]]"</span></pre></div>
<p dir="auto">Three examples wherein dtype-support is substantially more difficult to implement.</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="AR_3 = np.array(1.0)
AR_4 = np.array(1, dtype=float)
AR_5 = np.array(1, dtype=&quot;f8&quot;)

if TYPE_CHECKING:
    reveal_type(AR_3)  # note: Revealed type is &quot;numpy.ndarray[Any, numpy.dtype[Any]]&quot;
    reveal_type(AR_4)  # note: Revealed type is &quot;numpy.ndarray[Any, numpy.dtype[Any]]&quot;
    reveal_type(AR_5)  # note: Revealed type is &quot;numpy.ndarray[Any, numpy.dtype[Any]]&quot;"><pre class="notranslate"><span class="pl-v">AR_3</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">array</span>(<span class="pl-c1">1.0</span>)
<span class="pl-v">AR_4</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">array</span>(<span class="pl-c1">1</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s1">float</span>)
<span class="pl-v">AR_5</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">array</span>(<span class="pl-c1">1</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s">"f8"</span>)

<span class="pl-k">if</span> <span class="pl-v">TYPE_CHECKING</span>:
    <span class="pl-en">reveal_type</span>(<span class="pl-v">AR_3</span>)  <span class="pl-c"># note: Revealed type is "numpy.ndarray[Any, numpy.dtype[Any]]"</span>
    <span class="pl-en">reveal_type</span>(<span class="pl-v">AR_4</span>)  <span class="pl-c"># note: Revealed type is "numpy.ndarray[Any, numpy.dtype[Any]]"</span>
    <span class="pl-en">reveal_type</span>(<span class="pl-v">AR_5</span>)  <span class="pl-c"># note: Revealed type is "numpy.ndarray[Any, numpy.dtype[Any]]"</span></pre></div>
<p dir="auto">In the latter three cases one can always manually declare the dtype of the array:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import numpy.typing as npt

AR_6: npt.NDArray[np.float64] = np.array(1.0)

if TYPE_CHECKING:
    reveal_type(AR_6)  # note: Revealed type is &quot;numpy.ndarray[Any, numpy.dtype[numpy.floating*[numpy.typing._64Bit*]]]&quot;"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">numpy</span>.<span class="pl-s1">typing</span> <span class="pl-k">as</span> <span class="pl-s1">npt</span>

<span class="pl-v">AR_6</span>: <span class="pl-s1">npt</span>.<span class="pl-v">NDArray</span>[<span class="pl-s1">np</span>.<span class="pl-s1">float64</span>] <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">array</span>(<span class="pl-c1">1.0</span>)

<span class="pl-k">if</span> <span class="pl-v">TYPE_CHECKING</span>:
    <span class="pl-en">reveal_type</span>(<span class="pl-v">AR_6</span>)  <span class="pl-c"># note: Revealed type is "numpy.ndarray[Any, numpy.dtype[numpy.floating*[numpy.typing._64Bit*]]]"</span></pre></div>