一筋两堵 發表於 2019-6-4 02:43:00

TypeScript `unknown` 类型

<table class="d-block">
<tbody class="d-block">
    <tr class="d-block">
      <td class="d-block comment-body markdown-body js-comment-body rgh-linkified-code">
<p><code>unknown</code> 字面理解和 <code>any</code> 其实没差,任何类型都可赋值给它,但有一点,</p>
<blockquote>
<p>Anything is assignable to unknown, but unknown isn’t assignable to anything but itself and any without a type assertion or a control flow based narrowing</p>
<p><em>--TypeScript 3.0 Release notes - New unknown top type</em></p>
</blockquote>
<p><code>unknown</code> 类型不能赋值给除了 <code>unknown</code> 或 <code>any</code> 的其他任何类型,使用前必需显式进行指定类型,或是在有条件判断情况下能够隐式地进行类型推断的情况。</p>
<p>下面代码是合法的:</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">let</span> a<span class="pl-k">:</span> <span class="pl-c1">unknown</span>;
<span class="pl-k"><span class="pl-k">const</span></span> b<span class="pl-k">:</span> <span class="pl-c1">unknown</span> <span class="pl-k">=</span> <span class="pl-smi">a</span>;
<span class="pl-k"><span class="pl-k">const</span></span> c<span class="pl-k">:</span> <span class="pl-c1">any</span> <span class="pl-k">=</span> <span class="pl-smi">a</span>;</pre></div>
<p>因为 <code>unknown</code> 是可以赋值给 <code>unknown</code> 的,而下面的代码则不行,</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">let</span> a<span class="pl-k">:</span> <span class="pl-c1">unknown</span>;
<span class="pl-c"><span class="pl-c">//</span> 🚨Type 'unknown' is not assignable to type 'number'.ts(2322)</span>
<span class="pl-k"><span class="pl-k">const</span></span> b<span class="pl-k">:</span> <span class="pl-c1">number</span> <span class="pl-k">=</span> <span class="pl-smi">a</span>;</pre></div>
<p>但是如果使用时,明确知道了类型,则可以这样来修正:</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">let</span> a<span class="pl-k">:</span> <span class="pl-c1">unknown</span>;
<span class="pl-c"><span class="pl-c">//</span> 🚨Type 'unknown' is not assignable to type 'number'.ts(2322)</span>
<span class="pl-k"><span class="pl-k">const</span></span> b<span class="pl-k">:</span> <span class="pl-c1">number</span> <span class="pl-k">=</span> <span class="pl-smi">a</span>;</pre></div>
<p>或者在条件语句中,已经可以明确推断出类型:</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">let</span> a<span class="pl-k">:</span> <span class="pl-c1">unknown</span>;
<span class="pl-k">let</span> b<span class="pl-k">:</span> <span class="pl-c1">number</span> <span class="pl-k">=</span> &lt;<span class="pl-c1">number</span>&gt;<span class="pl-smi">a</span>;
<p><span class="pl-k">function</span> isNumber(<span class="pl-v">val</span><span class="pl-k">:</span> <span class="pl-c1">any</span>)<span class="pl-k">:</span> <span class="pl-en">val</span> <span class="pl-k">is</span> <span class="pl-c1">number</span> {<br>
<span class="pl-k">return</span> <span class="pl-k">typeof</span> <span class="pl-smi">val</span> <span class="pl-k">===</span> <span class="pl-s"><span class="pl-pds">"</span>number<span class="pl-pds">"</span></span>;<br>
}</p>
<p><span class="pl-k">if</span> (<span class="pl-en">isNumber</span>(<span class="pl-smi">a</span>)) {<br>
<span class="pl-smi">b</span> <span class="pl-k">=</span> <span class="pl-smi">a</span>;<br>
}</p></pre></div><p></p>
<p>所以在使用时,<code>unknown</code> 类型会比 <code>any</code> 更加安全。这个安全体现在,虽然它和 <code>any</code> 一样存储了任意类型的值,但是具体使用的时候,这个类型需要显式确定,由使用者进行指定将 <code>unknown</code> 转换成某一确定类型。</p>
<h2>优先级</h2>
<h3>与正交类型的搭配</h3>
<p>正交类型(intersection type)中,<code>unknown</code> 不起作用:</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">type</span> <span class="pl-en">T00</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">&amp;</span> <span class="pl-c1">null</span>;<span class="pl-c"><span class="pl-c">//</span> null</span>
<span class="pl-k">type</span> <span class="pl-en">T01</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">&amp;</span> <span class="pl-c1">undefined</span>;<span class="pl-c"><span class="pl-c">//</span> undefined</span>
<span class="pl-k">type</span> <span class="pl-en">T02</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">&amp;</span> <span class="pl-c1">null</span> <span class="pl-k">&amp;</span> <span class="pl-c1">undefined</span>;<span class="pl-c"><span class="pl-c">//</span> null &amp; undefined (which becomes never)</span>
<span class="pl-k">type</span> <span class="pl-en">T03</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">&amp;</span> <span class="pl-c1">string</span>;<span class="pl-c"><span class="pl-c">//</span> string</span>
<span class="pl-k">type</span> <span class="pl-en">T04</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">&amp;</span> <span class="pl-c1">string</span>[];<span class="pl-c"><span class="pl-c">//</span> string[]</span>
<span class="pl-k">type</span> <span class="pl-en">T05</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">&amp;</span> <span class="pl-c1">unknown</span>;<span class="pl-c"><span class="pl-c">//</span> unknown</span>
<span class="pl-k">type</span> <span class="pl-en">T06</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">&amp;</span> <span class="pl-c1">any</span>;<span class="pl-c"><span class="pl-c">//</span> any</span></pre></div>
<h3>与联合类型的搭配</h3>
<p>联合类型(union type)中 <code>unknown</code> 起绝对作用:</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">type</span> <span class="pl-en">T10</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">|</span> <span class="pl-c1">null</span>;<span class="pl-c"><span class="pl-c">//</span> unknown</span>
<span class="pl-k">type</span> <span class="pl-en">T11</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">|</span> <span class="pl-c1">undefined</span>;<span class="pl-c"><span class="pl-c">//</span> unknown</span>
<span class="pl-k">type</span> <span class="pl-en">T12</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">|</span> <span class="pl-c1">null</span> <span class="pl-k">|</span> <span class="pl-c1">undefined</span>;<span class="pl-c"><span class="pl-c">//</span> unknown</span>
<span class="pl-k">type</span> <span class="pl-en">T13</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">|</span> <span class="pl-c1">string</span>;<span class="pl-c"><span class="pl-c">//</span> unknown</span>
<span class="pl-k">type</span> <span class="pl-en">T14</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">|</span> <span class="pl-c1">string</span>[];<span class="pl-c"><span class="pl-c">//</span> unknown</span>
<span class="pl-k">type</span> <span class="pl-en">T15</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">|</span> <span class="pl-c1">unknown</span>;<span class="pl-c"><span class="pl-c">//</span> unknown</span>
<span class="pl-k">type</span> <span class="pl-en">T16</span> <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">|</span> <span class="pl-c1">any</span>;<span class="pl-c"><span class="pl-c">//</span> any</span></pre></div>
<p>上面仅一个例外,及和 <code>any</code> 组成的联合类型,最终结果是 <code>any</code>。</p>
<h3>使用在条件类型中</h3>
<p>条件类型(conditional type)中,</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">type</span> <span class="pl-en">T30</span>&lt;<span class="pl-en">T</span>&gt; <span class="pl-k">=</span> <span class="pl-c1">unknown</span> <span class="pl-k">extends</span> <span class="pl-en">T</span> <span class="pl-k">?</span> <span class="pl-c1">true</span> <span class="pl-k">:</span> <span class="pl-c1">false</span>;<span class="pl-c"><span class="pl-c">//</span> Deferred</span>
<span class="pl-k">type</span> <span class="pl-en">T31</span>&lt;<span class="pl-en">T</span>&gt; <span class="pl-k">=</span> <span class="pl-en">T</span> <span class="pl-k">extends</span> <span class="pl-c1">unknown</span> <span class="pl-k">?</span> <span class="pl-c1">true</span> <span class="pl-k">:</span> <span class="pl-c1">false</span>;<span class="pl-c"><span class="pl-c">//</span> Deferred (so it distributes)</span></pre></div>
<p>对于上面的条件类型,进行以下测试:</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-c"><span class="pl-c">//</span> `unknown` 不能赋值给 `number`</span>
<span class="pl-k">type</span> <span class="pl-en">foo</span> <span class="pl-k">=</span> <span class="pl-en">T30</span>&lt;<span class="pl-c1">number</span>&gt;; <span class="pl-c"><span class="pl-c">//</span> false</span>
<span class="pl-c"><span class="pl-c">//</span> `unknown` 可以赋值给 `any`</span>
<span class="pl-k">type</span> <span class="pl-en">bar</span> <span class="pl-k">=</span> <span class="pl-en">T30</span>&lt;<span class="pl-c1">any</span>&gt;; <span class="pl-c"><span class="pl-c">//</span> true</span>
<p><span class="pl-c"><span class="pl-c">//</span> 任何类型都可赋值给 <code>unknown</code>,所以都为 true</span><br>
<span class="pl-k">type</span> <span class="pl-en">a</span> <span class="pl-k">=</span> <span class="pl-en">T31</span>&lt;<span class="pl-c1">number</span>&gt;; <span class="pl-c"><span class="pl-c">//</span> true</span><br>
<span class="pl-k">type</span> <span class="pl-en">b</span> <span class="pl-k">=</span> <span class="pl-en">T31</span>&lt;<span class="pl-c1">any</span>&gt;; <span class="pl-c"><span class="pl-c">//</span> true</span></p></pre></div><p></p>
<h2>可进行的操作</h2>
<p>只能进行等于的判断,其他操作则会报错。</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">function</span> f10(<span class="pl-v">x</span><span class="pl-k">:</span> <span class="pl-c1">unknown</span>) {
    <span class="pl-smi">x</span> <span class="pl-k">==</span> <span class="pl-c1">5</span>;
    <span class="pl-smi">x</span> <span class="pl-k">!==</span> <span class="pl-c1">10</span>;
    <span class="pl-smi">x</span> <span class="pl-k">&gt;=</span> <span class="pl-c1">0</span>;<span class="pl-c"><span class="pl-c">//</span> Error</span>
    <span class="pl-smi">x</span> <span class="pl-k">+</span> <span class="pl-c1">1</span>;<span class="pl-c"><span class="pl-c">//</span> Error</span>
    <span class="pl-smi">x</span> <span class="pl-k">*</span> <span class="pl-c1">2</span>;<span class="pl-c"><span class="pl-c">//</span> Error</span>
    <span class="pl-k">-</span><span class="pl-smi">x</span>;<span class="pl-c"><span class="pl-c">//</span> Error</span>
    <span class="pl-k">+</span><span class="pl-smi">x</span>;<span class="pl-c"><span class="pl-c">//</span> Error</span>
}</pre></div>
<p>属性字段获取,方法调用等,也是不允许的:</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">function</span> f11(<span class="pl-v">x</span><span class="pl-k">:</span> <span class="pl-c1">unknown</span>) {
    <span class="pl-smi">x</span>.<span class="pl-smi">foo</span>;<span class="pl-c"><span class="pl-c">//</span> Error</span>
    <span class="pl-smi">x</span>[<span class="pl-c1">5</span>];<span class="pl-c"><span class="pl-c">//</span> Error</span>
    <span class="pl-en">x</span>();<span class="pl-c"><span class="pl-c">//</span> Error</span>
    <span class="pl-k">new</span> <span class="pl-en">x</span>();<span class="pl-c"><span class="pl-c">//</span> Error</span>
}</pre></div>
<p>当解构中有 <code>unknown</code> 类型时,会导致解构出来的结果也是 <code>unknown</code>。</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">function</span> f26(<span class="pl-v">x</span><span class="pl-k">:</span> {}, <span class="pl-v">y</span><span class="pl-k">:</span> <span class="pl-c1">unknown</span>, <span class="pl-v">z</span><span class="pl-k">:</span> <span class="pl-c1">any</span>) {
    <span class="pl-k">let</span> o1 <span class="pl-k">=</span> { a: <span class="pl-c1">42</span>, <span class="pl-k">...</span><span class="pl-smi">x</span> };<span class="pl-c"><span class="pl-c">//</span> { a: number }</span>
    <span class="pl-k">let</span> o2 <span class="pl-k">=</span> { a: <span class="pl-c1">42</span>, <span class="pl-k">...</span><span class="pl-smi">x</span>, <span class="pl-k">...</span><span class="pl-smi">y</span> };<span class="pl-c"><span class="pl-c">//</span> unknown</span>
    <span class="pl-k">let</span> o3 <span class="pl-k">=</span> { a: <span class="pl-c1">42</span>, <span class="pl-k">...</span><span class="pl-smi">x</span>, <span class="pl-k">...</span><span class="pl-smi">y</span>, <span class="pl-k">...</span><span class="pl-smi">z</span> };<span class="pl-c"><span class="pl-c">//</span> any</span>
}</pre></div>
<h2>具体使用场景</h2>
<p><code>unknown</code> 用于变量类型不确定,但肯定可以确定的情形下,比如下面这个示例中,入参总归会有个值,根据这个值的类型进行不同的处理,这里使用 <code>unknown</code> 替代 <code>any</code> 则会更加类型安全。</p>
<div class="highlight highlight-source-ts"><pre><span class="pl-k">function</span> prettyPrint(<span class="pl-v">x</span><span class="pl-k">:</span> <span class="pl-c1">unknown</span>)<span class="pl-k">:</span> <span class="pl-c1">string</span> {
<span class="pl-k">if</span> (<span class="pl-c1">Array</span>.<span class="pl-en">isArray</span>(<span class="pl-smi">x</span>)) {
    <span class="pl-k">return</span> <span class="pl-s"><span class="pl-pds">"</span>[<span class="pl-pds">"</span></span> <span class="pl-k">+</span> <span class="pl-smi">x</span>.<span class="pl-en">map</span>(<span class="pl-smi">prettyPrint</span>).<span class="pl-c1">join</span>(<span class="pl-s"><span class="pl-pds">"</span>, <span class="pl-pds">"</span></span>) <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">"</span>]<span class="pl-pds">"</span></span>
}
<span class="pl-k">if</span> (<span class="pl-k">typeof</span> <span class="pl-smi">x</span> <span class="pl-k">===</span> <span class="pl-s"><span class="pl-pds">"</span>string<span class="pl-pds">"</span></span>) {
    <span class="pl-k">return</span> <span class="pl-s"><span class="pl-pds">`</span>"${<span class="pl-smi">x</span>}"<span class="pl-pds">`</span></span>
}
<span class="pl-k">if</span> (<span class="pl-k">typeof</span> <span class="pl-smi">x</span> <span class="pl-k">===</span> <span class="pl-s"><span class="pl-pds">"</span>number<span class="pl-pds">"</span></span>) {
    <span class="pl-k">return</span> <span class="pl-c1">String</span>(<span class="pl-smi">x</span>)
}
<span class="pl-k">return</span> <span class="pl-s"><span class="pl-pds">"</span>etc.<span class="pl-pds">"</span></span>
}</pre></div>
<h2>相关资源</h2>
<ul>
<li>TypeScript 3.0 Release notes - New unknown top type</li>
<li>When to use <code>never</code> and <code>unknown</code> in TypeScript</li>
</ul>
      </td>
    </tr>
</tbody>
</table>

</div>
<div id="MySignature" role="contentinfo">
    <div>
<img src="https://licensebuttons.net/l/by-nc-sa/3.0/88x31.png" style="vertical-align: middle">
<strong>CC BY-NC-SA 署名-非商业性使用-相同方式共享</strong>
</div><br><br>
来源:https://www.cnblogs.com/Wayou/p/typescript_unknown_type.html
頁: [1]
查看完整版本: TypeScript `unknown` 类型