梁丽萍 發表於 2022-9-21 14:21:00

TypeScript学习笔记(二)—— TypeScript基础

<h1>一、原始数据类型基本使用</h1>
<p>TypeScript中拥有更多的类型,如下表所示:</p>
<table>
<thead>
<tr><th>类型</th><th>例子</th><th>描述</th></tr>
</thead>
<tbody>
<tr>
<td>number</td>
<td>1, -33, 2.5</td>
<td>任意数字</td>
</tr>
<tr>
<td>string</td>
<td>'hi', "hi",&nbsp;<code>hi</code></td>
<td>任意字符串</td>
</tr>
<tr>
<td>boolean</td>
<td>true、false</td>
<td>布尔值true或false</td>
</tr>
<tr>
<td>字面量</td>
<td>其本身</td>
<td>限制变量的值就是该字面量的值</td>
</tr>
<tr>
<td>any</td>
<td>*</td>
<td>任意类型</td>
</tr>
<tr>
<td>unknown</td>
<td>*</td>
<td>类型安全的any</td>
</tr>
<tr>
<td>void</td>
<td>空值(undefined)</td>
<td>没有值(或undefined)</td>
</tr>
<tr>
<td>never</td>
<td>没有值</td>
<td>不能是任何值</td>
</tr>
<tr>
<td>object</td>
<td>{name:'孙悟空'}</td>
<td>任意的JS对象</td>
</tr>
<tr>
<td>array</td>
<td></td>
<td>任意JS数组</td>
</tr>
<tr>
<td>tuple</td>
<td></td>
<td>元素,TS新增类型,固定长度数组</td>
</tr>
<tr>
<td>enum</td>
<td>enum{A, B}</td>
<td>枚举,TS中新增类型</td>
</tr>
</tbody>
</table>
<p>JavaScript 的类型分为两种:原始数据类型(Primitive data types)和对象类型(Object types)。</p>
<p>原始数据类型包括:布尔值、数值、字符串、null、undefined 以及&nbsp;ES6 中的新类型 Symbol。</p>
<p>本节主要介绍前五种原始数据类型在 TypeScript 中的应用。</p>
<p><strong>javascript原始类型:布尔值、数值、字符串、null、undefined</strong>,为变量指定类型,且变量值需与类型一致</p>
<pre class="highlighter-hljs"><code class="highlighter-hljs hljs language-typescript"><span class="hljs-keyword">let <span class="hljs-attr">flag: <span class="hljs-built_in">boolean = <span class="hljs-literal">false
<span class="hljs-keyword">let <span class="hljs-attr">num: <span class="hljs-built_in">number = <span class="hljs-number">15
<span class="hljs-keyword">let <span class="hljs-attr">str: <span class="hljs-built_in">string = <span class="hljs-string">'abc'
<span class="hljs-keyword">var <span class="hljs-attr">a: <span class="hljs-literal">null = <span class="hljs-literal">null
<span class="hljs-keyword">var <span class="hljs-attr">b: <span class="hljs-literal">undefined = <span class="hljs-literal">undefined

<span class="hljs-comment">// 编译通过
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>使用构造函数创造的对象不是原始数据类型,<strong>事实上 new XXX() 返回的是一个 XXX对象</strong>:</p>
<pre class="highlighter-hljs"><code class="language-js highlighter-hljs hljs language-javascript"><span class="hljs-keyword">let <span class="hljs-attr">flag:boolean=<span class="hljs-keyword">new <span class="hljs-title class_">Boolean(<span class="hljs-literal">false)<span class="hljs-comment">// Type 'Boolean' is not assignable to type 'boolean'.
<span class="hljs-keyword">let <span class="hljs-attr">num: number = <span class="hljs-keyword">new <span class="hljs-title class_">Number(<span class="hljs-number">15)   <span class="hljs-comment">// Type 'Number' is not assignable to type 'number'.
<span class="hljs-keyword">let <span class="hljs-attr">str: string = <span class="hljs-keyword">new <span class="hljs-title class_">String(<span class="hljs-string">'abc')<span class="hljs-comment">// Type 'String' is not assignable to type 'string'.

<span class="hljs-comment">// 编译通过
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>但是可以直接<strong>调用 XXX</strong>&nbsp;也可以<strong>返回一个 xxx 类型</strong>:</p>
<pre class="highlighter-hljs"><code class="highlighter-hljs hljs language-typescript"><span class="hljs-keyword">let <span class="hljs-attr">flag: <span class="hljs-built_in">boolean = <span class="hljs-title class_">Boolean(<span class="hljs-literal">false)
<span class="hljs-keyword">let num : <span class="hljs-built_in">number= <span class="hljs-title class_">Number(<span class="hljs-number">15)
<span class="hljs-keyword">let str : <span class="hljs-built_in">string= <span class="hljs-title class_">String(<span class="hljs-string">'abc')
<span class="hljs-comment">// 编译通过<br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">javascript 中的数据类型分为:原始数据类型 与 对象数据类型</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)">原始数据类型:number,string,boolean,null,undefined,symbol,bigInt</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)">对象数据类型:Array,Object,RegExp...</span>
let n:number=1<span style="color: rgba(0, 0, 0, 1)">;
let s:string</span>="hello"<span style="color: rgba(0, 0, 0, 1)">;
let b:</span><span style="color: rgba(0, 0, 255, 1)">boolean</span>=<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
let nu:</span><span style="color: rgba(0, 0, 255, 1)">null</span>=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
let und:undefined</span>=<span style="color: rgba(0, 0, 0, 1)">undefined;
let sy:symbol</span>=<span style="color: rgba(0, 0, 0, 1)">Symbol();
let o:Object</span>=<span style="color: rgba(0, 0, 0, 1)">{};

let num:number;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">num=new Number(100);//错误,new Number实例化生成的数据类型是Object类型</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)">new String("");//Object类型</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)">new Boolean("true");//Object类型</span>
<span style="color: rgba(0, 0, 0, 1)">

let a:number;
a</span>=Number(200);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">直接调用函数Number返回的是number类型的数据</span>
<span style="color: rgba(0, 0, 0, 1)">
let c:string;
c</span>=String("hi");<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">直接调用String函数返回的是string类型的数据</span>
<span style="color: rgba(0, 0, 0, 1)">
let d:</span><span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)">;
d</span>=Boolean(<span style="color: rgba(0, 0, 255, 1)">false</span>);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">直接调用Boolean函数返回的是boolean类型的数据</span></pre>
</div>
<h1>二、原始数据类型</h1>
<p>JavaScript 的类型分为两种:原始数据类型(Primitive data types)和对象类型(Object types)。</p>
<p>原始数据类型包括:布尔值、数值、字符串、<code>null</code>、<code>undefined</code>&nbsp;以及 ES6 中的新类型&nbsp;<code>Symbol</code>&nbsp;和 ES10 中的新类型&nbsp;<code>BigInt</code>。</p>
<p>本节主要介绍前五种原始数据类型在 TypeScript 中的应用。</p>
<h2 id="%E5%B8%83%E5%B0%94%E5%80%BC">2.1、布尔值<br></h2>
<p>布尔值是最基础的数据类型,在 TypeScript 中,使用&nbsp;<code>boolean</code>&nbsp;定义布尔值类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let isDone<span class="token operator">: <span class="token builtin">boolean <span class="token operator">= <span class="token boolean">false<span class="token punctuation">;

<span class="token comment">// 编译通过
<span class="token comment">// 后面约定,未强调编译错误的代码片段,默认为编译通过
</span></span></span></span></span></span></span></span></code></pre>
<p>注意,使用构造函数&nbsp;<code>Boolean</code>&nbsp;创造的对象不是布尔值:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let createdByNewBoolean<span class="token operator">: <span class="token builtin">boolean <span class="token operator">= <span class="token keyword">new <span class="token class-name">Boolean<span class="token punctuation">(<span class="token number">1<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// Type 'Boolean' is not assignable to type 'boolean'.
<span class="token comment">//   'boolean' is a primitive, but 'Boolean' is a wrapper object. Prefer using 'boolean' when possible.
</span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>事实上&nbsp;<code>new Boolean()</code>&nbsp;返回的是一个&nbsp;<code>Boolean</code>&nbsp;对象:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let createdByNewBoolean<span class="token operator">: Boolean <span class="token operator">= <span class="token keyword">new <span class="token class-name">Boolean<span class="token punctuation">(<span class="token number">1<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></code></pre>
<p>直接调用&nbsp;<code>Boolean</code>&nbsp;也可以返回一个&nbsp;<code>boolean</code>&nbsp;类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let createdByBoolean<span class="token operator">: <span class="token builtin">boolean <span class="token operator">= <span class="token function">Boolean<span class="token punctuation">(<span class="token number">1<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></code></pre>
<p>在 TypeScript 中,<code>boolean</code>&nbsp;是 JavaScript 中的基本类型,而&nbsp;<code>Boolean</code>&nbsp;是 JavaScript 中的构造函数。其他基本类型(除了&nbsp;<code>null</code>&nbsp;和&nbsp;<code>undefined</code>)一样,不再赘述。</p>
<div class="cnblogs_code">
<pre>let isShow=<span style="color: rgba(0, 0, 255, 1)">true</span>;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">推断类型,isShow根据值被编译器推断为boolean类型</span>

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">isShow=1;//错误不能将类型“number”分配给类型“boolean”。ts(2322)</span>

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">isShow=new Boolean(true);//错误,返回的是Object</span>
<span style="color: rgba(0, 0, 0, 1)">
isShow</span>=Boolean(1);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">正确的,返回的是boolean类型的false</span>
<span style="color: rgba(0, 0, 0, 1)">
isShow</span>=Boolean(0);   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">false</span>
<span style="color: rgba(0, 0, 0, 1)">
isShow</span>=Boolean(undefined); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">false</span>
<span style="color: rgba(0, 0, 0, 1)">
isShow</span>=Boolean(<span style="color: rgba(0, 0, 255, 1)">null</span>); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">false</span>
<span style="color: rgba(0, 0, 0, 1)">
isShow</span>=Boolean(""); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">false</span>
<span style="color: rgba(0, 0, 0, 1)">
isShow</span>=Boolean({}); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">true</span>
<span style="color: rgba(0, 0, 0, 1)">
console.log(isShow); </span></pre>
</div>
<h2 id="%E6%95%B0%E5%80%BC">2.2、数值<br></h2>
<p>使用&nbsp;<code>number</code>&nbsp;定义数值类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let decLiteral<span class="token operator">: <span class="token builtin">number <span class="token operator">= <span class="token number">6<span class="token punctuation">;
<span class="token keyword">let hexLiteral<span class="token operator">: <span class="token builtin">number <span class="token operator">= <span class="token number">0xf00d<span class="token punctuation">;
<span class="token comment">// ES6 中的二进制表示法
<span class="token keyword">let binaryLiteral<span class="token operator">: <span class="token builtin">number <span class="token operator">= <span class="token number">0b1010<span class="token punctuation">;
<span class="token comment">// ES6 中的八进制表示法
<span class="token keyword">let octalLiteral<span class="token operator">: <span class="token builtin">number <span class="token operator">= <span class="token number">0o744<span class="token punctuation">;
<span class="token keyword">let notANumber<span class="token operator">: <span class="token builtin">number <span class="token operator">= <span class="token number">NaN<span class="token punctuation">;
<span class="token keyword">let infinityNumber<span class="token operator">: <span class="token builtin">number <span class="token operator">= <span class="token number">Infinity<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>编译结果:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var decLiteral <span class="token operator">= <span class="token number">6<span class="token punctuation">;
<span class="token keyword">var hexLiteral <span class="token operator">= <span class="token number">0xf00d<span class="token punctuation">;
<span class="token comment">// ES6 中的二进制表示法
<span class="token keyword">var binaryLiteral <span class="token operator">= <span class="token number">10<span class="token punctuation">;
<span class="token comment">// ES6 中的八进制表示法
<span class="token keyword">var octalLiteral <span class="token operator">= <span class="token number">484<span class="token punctuation">;
<span class="token keyword">var notANumber <span class="token operator">= <span class="token number">NaN<span class="token punctuation">;
<span class="token keyword">var infinityNumber <span class="token operator">= <span class="token number">Infinity<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>其中&nbsp;<code>0b1010</code>&nbsp;和&nbsp;<code>0o744</code>&nbsp;是&nbsp;ES6 中的二进制和八进制表示法,它们会被编译为十进制数字。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">数值 number Number</span>
<span style="color: rgba(0, 0, 0, 1)">
let n1:number</span>=10;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">十进制</span>
let n2:number=0xFFF;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">十六进制</span>
let n3:number=0o176;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">八进制</span>
let n4:number=0b1101; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">二进制</span>
let n5:number=15.6;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">小数,浮点数</span>
let n6:number=NaN; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">非数字</span>
let n7:number=Infinity; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">无限大</span>

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">n1=new Number(100);//错误,返回的Object类型</span>
<span style="color: rgba(0, 0, 0, 1)">
n1</span>=Number("200");<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">正确</span>
<span style="color: rgba(0, 0, 0, 1)">
console.log(n1);</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">200</span></pre>
</div>
<h2 id="%E5%AD%97%E7%AC%A6%E4%B8%B2">2.3、字符串<br></h2>
<p>使用&nbsp;<code>string</code>&nbsp;定义字符串类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let myName<span class="token operator">: <span class="token builtin">string <span class="token operator">= <span class="token string">'Tom'<span class="token punctuation">;
<span class="token keyword">let myAge<span class="token operator">: <span class="token builtin">number <span class="token operator">= <span class="token number">25<span class="token punctuation">;

<span class="token comment">// 模板字符串
<span class="token keyword">let sentence<span class="token operator">: <span class="token builtin">string <span class="token operator">= <span class="token template-string"><span class="token template-punctuation string">`<span class="token string">Hello, my name is <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${myName<span class="token interpolation-punctuation punctuation">}<span class="token string">.
I'll be <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${myAge <span class="token operator">+ <span class="token number">1<span class="token interpolation-punctuation punctuation">}<span class="token string"> years old next month.<span class="token template-punctuation string">`<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>编译结果:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var myName <span class="token operator">= <span class="token string">'Tom'<span class="token punctuation">;
<span class="token keyword">var myAge <span class="token operator">= <span class="token number">25<span class="token punctuation">;
<span class="token comment">// 模板字符串
<span class="token keyword">var sentence <span class="token operator">= <span class="token string">"Hello, my name is " <span class="token operator">+ myName <span class="token operator">+ <span class="token string">".
I'll be " <span class="token operator">+ <span class="token punctuation">(myAge <span class="token operator">+ <span class="token number">1<span class="token punctuation">) <span class="token operator">+ <span class="token string">" years old next month."<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>其中&nbsp;<code>`</code>&nbsp;用来定义&nbsp;ES6 中的模板字符串,<code>${expr}</code>&nbsp;用来在模板字符串中嵌入表达式。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">字符串 string String</span>
<span style="color: rgba(0, 0, 0, 1)">
let studentname:string</span>="tom"<span style="color: rgba(0, 0, 0, 1)">;
let studentage:number</span>=18<span style="color: rgba(0, 0, 0, 1)">;

let result</span>=`我叫${studentname},明年${++<span style="color: rgba(0, 0, 0, 1)">studentage}岁`;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">result=100;//错误,因为模板字符串被推断为string数据类型</span>
console.log(result);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">我叫tom,明年19岁</span>
<span style="color: rgba(0, 0, 0, 1)">
let a</span>=<span style="color: rgba(0, 0, 255, 1)">new</span> String("hello world"<span style="color: rgba(0, 0, 0, 1)">);
console.log(</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> a);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">object</span>

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">let b:string=new String("hello world"); //不能将类型“String”分配给类型“string”。 object</span>
<span style="color: rgba(0, 0, 0, 1)">
let c:string</span>=String(<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
console.log(c);</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">true</span></pre>
</div>
<h2 id="%E7%A9%BA%E5%80%BC">2.4、空值<br></h2>
<p>JavaScript 没有空值(Void)的概念,在 TypeScript 中,可以用&nbsp;<code>void</code>&nbsp;表示没有任何返回值的函数:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">alertName<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void <span class="token punctuation">{
    <span class="token function">alert<span class="token punctuation">(<span class="token string">'My name is Tom'<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>声明一个&nbsp;<code>void</code>&nbsp;类型的变量没有什么用,因为你只能将它赋值为&nbsp;<code>undefined</code>&nbsp;和&nbsp;<code>null</code>(只在 --strictNullChecks 未指定时):</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let unusable<span class="token operator">: <span class="token keyword">void <span class="token operator">= <span class="token keyword">undefined<span class="token punctuation">;<br></span></span></span></span></span></span></code></pre>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">void 空值</span>
<span style="color: rgba(0, 0, 0, 1)">
let a:</span><span style="color: rgba(0, 0, 255, 1)">void</span>=undefined;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">一般不会使用在变量类型的定义中</span>

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">a=null;//默认错误</span>


<span style="color: rgba(0, 0, 255, 1)">function</span> f1():<span style="color: rgba(0, 0, 255, 1)">void</span>{<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">表明函数没有返回值</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">return 100;//不允许</span>
}</pre>
</div>
<h2 id="null-%E5%92%8C-undefined">2.5、Null 和 Undefined<br></h2>
<p>在 TypeScript 中,可以使用&nbsp;<code>null</code>&nbsp;和&nbsp;<code>undefined</code>&nbsp;来定义这两个原始数据类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let u<span class="token operator">: <span class="token keyword">undefined <span class="token operator">= <span class="token keyword">undefined<span class="token punctuation">;
<span class="token keyword">let n<span class="token operator">: <span class="token keyword">null <span class="token operator">= <span class="token keyword">null<span class="token punctuation">;<br></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">null,undefined</span>
<span style="color: rgba(0, 0, 0, 1)">
let n1:</span><span style="color: rgba(0, 0, 255, 1)">null</span>=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">n1=undefined;//错误</span>
<span style="color: rgba(0, 0, 0, 1)">
let n2:undefined</span>=<span style="color: rgba(0, 0, 0, 1)">undefined;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">n2=null;//错误</span></pre>
</div>
<h2>2.6、Infinity无穷大</h2>
<p>Infinity(无穷大)在 JS 中是一个特殊的数字,它的特性是:它比任何有限的数字都大,在 Javascript 中,超出&nbsp;<strong>1.797693134862315E+308</strong>&nbsp;的数值即为 Infinity,小于&nbsp;<strong>-1.797693134862316E+308</strong>&nbsp;的数值为无穷小。</p>
<p><strong>1.Infinity(无穷)的定义<br></strong></p>
<p>无穷可以分为两种,正无穷和负无穷,JS 中对应的表示方式为:+Infinity(或者Infinity) 和 -Infinity。</p>
<p>这意味着Infinity和-Infinity(小于任何有限数的数字)都是number类型的特殊值:</p>
<div class="jb51code">
<div>
<div id="highlighter_622598" class="syntaxhighlighterjs">
<div class="line number1 index0 alt2"><code class="js keyword">typeof</code>&nbsp;<code class="js plain">Infinity;&nbsp;</code><code class="js comments">// =&gt; 'number'</code></div>
<div class="line number2 index1 alt1"><code class="js keyword">typeof</code>&nbsp;<code class="js plain">-Infinity;&nbsp;</code><code class="js comments">// =&gt; 'number'</code></div>








































</div>








































</div>








































</div>
<p>Infinity 是全局对象的属性:</p>
<p>window.Infinity; // =&gt; Infinity</p>
<p>另外,Number函数也有两个属性来表示正负无穷大:</p>
<blockquote>
<p>Number.POSITIVE_INFINITY; // =&gt; Infinity<br>Number.NEGATIVE_INFINITY; // =&gt; -Infinity</p>








































</blockquote>
<p><strong>2. Infinity 的特性</strong></p>
<p>Infinity比任何有限数都大。</p>
<p>举几个例子 :</p>
<blockquote>
<p>Infinity &gt; 100;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // =&gt; true<br>Infinity &gt; Number.MAX_SAFE_INTEGER; // =&gt; true<br>Infinity &gt; Number.MAX_VALUE;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // =&gt; true</p>








































</blockquote>
<p><code>Number.MAX_SAFE_INTEGER</code>&nbsp;常量表示在&nbsp;JavaScript 中最大的安全整数(maxinum safe integer)(<code>2^53 - 1),数值,9007199254740991。</code></p>
<p>Infinity 在加法、乘法和除法等算术运算中用作操作数时会产生有趣的效果:</p>
<blockquote>
<p>Infinity + 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // =&gt; Infinity<br>Infinity + Infinity; // =&gt; Infinity</p>
<p>Infinity * 2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // =&gt; Infinity<br>Infinity * Infinity; // =&gt; Infinity</p>
<p>Infinity / 2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // =&gt; Infinity</p>








































</blockquote>
<p>一些Infinity 的运算得到有限的数:</p>
<blockquote>
<p>10 / Infinity; // =&gt; 0</p>








































</blockquote>
<p>一个有限的数除以0得到 Infinity 结果:</p>
<blockquote>
<p>2 / 0; // =&gt; Infinity</p>








































</blockquote>
<p>对无穷数进行概念上不正确的运算会得到NaN。 例如,不能除以无限数,也无法确定无限数是奇数还是偶数:</p>
<blockquote>
<p>Infinity / Infinity; // =&gt; NaN<br>Infinity % 2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // =&gt; NaN</p>








































</blockquote>
<p><strong>2.1 负无穷</strong></p>
<p>负无穷小于任何有限数。</p>
<p>将-Infinity 与一些有限数字进行比较:</p>
<blockquote>
<p>-Infinity &lt; 100;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // =&gt; true<br>-Infinity &lt; -Number.MAX_SAFE_INTEGER; // =&gt; true<br>-Infinity &lt; -Number.MAX_VALUE;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // =&gt; true</p>








































</blockquote>
<p>同时,负无穷小于正无穷:</p>
<p>-Infinity &lt; Infinity; // =&gt; true</p>
<p>当使用不同操作符操作数时,也可能会得到负无穷:</p>
<blockquote>
<p>Infinity * -1; // =&gt; -Infinity<br>Infinity / -2; // =&gt; -Infinity<br>-2 / 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // =&gt; -Infinity</p>








































</blockquote>
<p><strong>3.判断无穷</strong></p>
<p>幸运的是,Infinity等于相同符号的Infinity:</p>
<blockquote>
<p>Infinity === Infinity; // =&gt; true<br>-Infinity === -Infinity; // =&gt; true</p>








































</blockquote>
<p>但前面的符号不一样就不相等,就也很好理解:</p>
<blockquote>
<p>Infinity === -Infinity; // =&gt; false</p>








































</blockquote>
<p>JSt有一个特殊的函数Number.isFinite(value),用于检查提供的值是否有限数:</p>
<blockquote>
<p>Number.isFinite(Infinity);&nbsp; // =&gt; false<br>Number.isFinite(-Infinity); // =&gt; false<br>Number.isFinite(999);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // =&gt; true</p>








































</blockquote>
<h2>2.7、Number的属性</h2>
<table class="table table-bordered table-striped-alt">
<tbody>
<tr class="firstRow"><th>属性</th><th>描述</th></tr>
<tr>
<td>constructor</td>
<td>返回对创建对象的Number函数的引用</td>






































</tr>
<tr>
<td>MAX_VALUE</td>
<td>返回JavaScript中最大数字</td>






































</tr>
<tr>
<td>MIN_VALUE</td>
<td>返回JavaScript中最小数字</td>






































</tr>
<tr>
<td>MAX_SAFE_INTEGER</td>
<td>返回JavaScript中的最大安全整数(2&nbsp;53-1)</td>






































</tr>
<tr>
<td>MIN_SAFE_INTEGER</td>
<td>返回在JavaScript中最小安全整数(-2&nbsp;53&nbsp;- 1)</td>






































</tr>
<tr>
<td>NaN</td>
<td>代表“非数字”值</td>






































</tr>
<tr>
<td>NEGATIVE_INFINITY</td>
<td>表示负无穷大(溢出时返回)</td>






































</tr>
<tr>
<td>POSITIVE_INFINITY</td>
<td>表示正无穷大(溢出时返回)</td>






































</tr>
<tr>
<td>prototype</td>
<td>允许您向对象添加属性和方法</td>






































</tr>






































</tbody>






































</table>
<p>&nbsp;</p>
<h1>三、任意值</h1>
<p>在typescript中,当我们不确定一个类型是什么类型的,可以选择给其声明为any或者unkown。但实际上,typescript推荐使用unknown,因为unknown是类型安全的。</p>
<p>任意值(Any)用来表示允许赋值为任意类型。</p>
<h2 id="%E4%BB%80%E4%B9%88%E6%98%AF%E4%BB%BB%E6%84%8F%E5%80%BC%E7%B1%BB%E5%9E%8B">3.1、什么是任意值类型<br></h2>
<p>如果是一个普通类型,在赋值过程中改变类型是不被允许的:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let myFavoriteNumber<span class="token operator">: <span class="token builtin">string <span class="token operator">= <span class="token string">'seven'<span class="token punctuation">;
myFavoriteNumber <span class="token operator">= <span class="token number">7<span class="token punctuation">;

<span class="token comment">// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
</span></span></span></span></span></span></span></span></span></span></code></pre>
<p>但如果是&nbsp;<code>any</code>&nbsp;类型,则允许被赋值为任意类型。</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let myFavoriteNumber<span class="token operator">: <span class="token builtin">any <span class="token operator">= <span class="token string">'seven'<span class="token punctuation">;
myFavoriteNumber <span class="token operator">= <span class="token number">7<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></code></pre>
<h2 id="%E4%BB%BB%E6%84%8F%E5%80%BC%E7%9A%84%E5%B1%9E%E6%80%A7%E5%92%8C%E6%96%B9%E6%B3%95">3.2、任意值的属性和方法<br></h2>
<p>在任意值上访问任何属性都是允许的:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let anyThing<span class="token operator">: <span class="token builtin">any <span class="token operator">= <span class="token string">'hello'<span class="token punctuation">;
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(anyThing<span class="token punctuation">.myName<span class="token punctuation">)<span class="token punctuation">;//undefined</span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>可以认为,声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。</p>
<h2 id="%E6%9C%AA%E5%A3%B0%E6%98%8E%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8F%98%E9%87%8F">3.3、未声明类型的变量<br></h2>
<p>变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let something<span class="token punctuation">;
something <span class="token operator">= <span class="token string">'seven'<span class="token punctuation">;
something <span class="token operator">= <span class="token number">7<span class="token punctuation">;

something<span class="token punctuation">.<span class="token function">setName<span class="token punctuation">(<span class="token string">'Tom'<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>等价于</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let something<span class="token operator">: <span class="token builtin">any<span class="token punctuation">;
something <span class="token operator">= <span class="token string">'seven'<span class="token punctuation">;
something <span class="token operator">= <span class="token number">7<span class="token punctuation">;

something<span class="token punctuation">.<span class="token function">setName<span class="token punctuation">(<span class="token string">'Tom'<span class="token punctuation">)<span class="token punctuation">;<br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 id="%E6%9C%AA%E5%A3%B0%E6%98%8E%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8F%98%E9%87%8F">3.4、任意值可以赋值给已知类型变量</h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">let a:number;
a</span>=100<span style="color: rgba(0, 0, 0, 1)">;

let b:any;
b</span>=200<span style="color: rgba(0, 0, 0, 1)">;
b</span>="hello world"<span style="color: rgba(0, 0, 0, 1)">;

a</span>=<span style="color: rgba(0, 0, 0, 1)">b;

console.log(</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> a);</pre>
</div>
<p>结果</p>
<p><img src="https://img2022.cnblogs.com/blog/63651/202209/63651-20220921144530050-578048292.png" alt="" width="672" height="106" loading="lazy"></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">let a:any;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">可以将任意类型赋值给any类型</span>
a=7<span style="color: rgba(0, 0, 0, 1)">;
a</span>="hi"<span style="color: rgba(0, 0, 0, 1)">;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">任意类型可以接收any类型的值</span>
let b:<span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)">;
b</span>=<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;

b</span>=a;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">注意这里是正确的,b的类型已改变成a的类型string,注意不是any</span>

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">b=8;//错误</span>
<span style="color: rgba(0, 0, 0, 1)">
console.log(</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> b); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">string</span>

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果在定义变量时没有指定类型,则变量为any类型</span>
let c;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里相当于 let c:any</span>
<span style="color: rgba(0, 0, 255, 1)">function</span> f1(a,b,c){<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">function f1(a: any, b: any, c: any): void</span>
}</pre>
</div>
<h2>3.5、unknown</h2>
<ul>
<li>
<pre class="language-typescript" data-role="codeBlock" data-info="typescript"><span class="token keyword keyword-let">let notSure<span class="token operator">: <span class="token builtin">unknown <span class="token operator">= <span class="token number">4<span class="token punctuation">;
notSure <span class="token operator">= <span class="token string">'hello'<span class="token punctuation">;</span></span></span></span></span></span></span></span></span></pre>
</li>
</ul>
<div>
<p>any是任意类型的父类型,同时也任意类型的子类型<br>unknown是任意类型的父类型,但仅此而已。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">let a:unknown;
let b:number;

a</span>=1<span style="color: rgba(0, 0, 0, 1)">;
a</span>="hello world"<span style="color: rgba(0, 0, 0, 1)">;

b</span>=a;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">错误</span></pre>
</div>
<p>示例2</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">let a:unknown;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">unknown类型可以被赋值为任意类型这点与any类似</span>
<span style="color: rgba(0, 0, 0, 1)">
a</span>=7<span style="color: rgba(0, 0, 0, 1)">;
a</span>=<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
a</span>="hello"<span style="color: rgba(0, 0, 0, 1)">;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">但是其它类型不能接收unknown的值,不能将unknown赋值给其它类</span>
let b:<span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)">;
b</span>=<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;

b</span>=a;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">错误,如果a是any类型则允许</span></pre>
</div>
<h2>3.6、nerver</h2>
<ul>
<li>
<pre class="language-typescript" data-role="codeBlock" data-info="typescript"><span class="token keyword keyword-function">function <span class="token function">error<span class="token punctuation">(message<span class="token operator">: <span class="token builtin">string<span class="token punctuation">)<span class="token operator">: <span class="token builtin">never <span class="token punctuation">{
<span class="token keyword keyword-throw">throw <span class="token keyword keyword-new">new <span class="token class-name">Error<span class="token punctuation">(message<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
</li>
</ul>
<div>
<div>
<p>永远都不会有返回的函数:</p>
<p>1、函数抛出异常</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> a () {
    </span><span style="color: rgba(0, 0, 255, 1)">throw</span> TypeError('this is a error'<span style="color: rgba(0, 0, 0, 1)">)
}</span></pre>
</div>
<p>2、永远执行下去的函数</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> b() {
    </span><span style="color: rgba(0, 0, 255, 1)">while</span>(<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> todo</span>
<span style="color: rgba(0, 0, 0, 1)">    }
}</span></pre>
</div>
</div>
</div>
</div>
<h1>四、类型推论</h1>
<p>如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。</p>
<p>以下代码虽然没有指定类型,但是会在编译的时候报错:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let myFavoriteNumber <span class="token operator">= <span class="token string">'seven'<span class="token punctuation">;
myFavoriteNumber <span class="token operator">= <span class="token number">7<span class="token punctuation">;

<span class="token comment">// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
</span></span></span></span></span></span></span></span></code></pre>
<p>事实上,它等价于:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let myFavoriteNumber<span class="token operator">: <span class="token builtin">string <span class="token operator">= <span class="token string">'seven'<span class="token punctuation">;
myFavoriteNumber <span class="token operator">= <span class="token number">7<span class="token punctuation">;

<span class="token comment">// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
</span></span></span></span></span></span></span></span></span></span></code></pre>
<p>TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推论。</p>
<p>如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成&nbsp;<code>any</code>&nbsp;类型而完全不被类型检查:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let myFavoriteNumber<span class="token punctuation">;
myFavoriteNumber <span class="token operator">= <span class="token string">'seven'<span class="token punctuation">;
myFavoriteNumber <span class="token operator">= <span class="token number">7<span class="token punctuation">;<br><br></span></span></span></span></span></span></span></span></code></pre>
<div class="cnblogs_code">
<pre>let a=100;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">a被推断为number 等同于let a:number=100;</span>
<span style="color: rgba(0, 0, 0, 1)">
let b</span>=<span style="color: rgba(0, 0, 255, 1)">true</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">b被推断为boolean类型</span>
<span style="color: rgba(0, 0, 0, 1)">
let c;

c</span>="hello"<span style="color: rgba(0, 0, 0, 1)">;

console.log(</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> c);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">string</span>

<span style="color: rgba(0, 0, 255, 1)">function</span> f1(){<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">函数的返回值被推断为number,相当于f1():number</span>
    <span style="color: rgba(0, 0, 255, 1)">return</span> 1<span style="color: rgba(0, 0, 0, 1)">;
}</span></pre>
</div>
<h1>五、联合类型</h1>
<p>联合类型(Union Types)表示取值可以为多种类型中的一种。</p>
<h2 id="%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%8B%E5%AD%90">5.1、简单的例子<br></h2>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let myFavoriteNumber<span class="token operator">: <span class="token builtin">string <span class="token operator">| <span class="token builtin">number<span class="token punctuation">;
myFavoriteNumber <span class="token operator">= <span class="token string">'seven'<span class="token punctuation">;
myFavoriteNumber <span class="token operator">= <span class="token number">7<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let myFavoriteNumber<span class="token operator">: <span class="token builtin">string <span class="token operator">| <span class="token builtin">number<span class="token punctuation">;
myFavoriteNumber <span class="token operator">= <span class="token boolean">true<span class="token punctuation">;

<span class="token comment">// index.ts(2,1): error TS2322: Type 'boolean' is not assignable to type 'string | number'.
<span class="token comment">//   Type 'boolean' is not assignable to type 'number'.
</span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>联合类型使用&nbsp;<code>|</code>&nbsp;分隔每个类型。</p>
<p>这里的&nbsp;<code>let myFavoriteNumber: string | number</code>&nbsp;的含义是,允许&nbsp;<code>myFavoriteNumber</code>&nbsp;的类型是&nbsp;<code>string</code>&nbsp;或者&nbsp;<code>number</code>,但是不能是其他类型。</p>
<h2 id="%E8%AE%BF%E9%97%AE%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%B1%9E%E6%80%A7%E6%88%96%E6%96%B9%E6%B3%95">5.2、访问联合类型的属性或方法<br></h2>
<p>当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">getLength<span class="token punctuation">(something<span class="token operator">: <span class="token builtin">string <span class="token operator">| <span class="token builtin">number<span class="token punctuation">)<span class="token operator">: <span class="token builtin">number <span class="token punctuation">{
    <span class="token keyword">return something<span class="token punctuation">.length<span class="token punctuation">;
<span class="token punctuation">}

<span class="token comment">// index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'.
<span class="token comment">//   Property 'length' does not exist on type 'number'.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上例中,<code>length</code>&nbsp;不是&nbsp;<code>string</code>&nbsp;和&nbsp;<code>number</code>&nbsp;的共有属性,所以会报错。</p>
<p>访问&nbsp;<code>string</code>&nbsp;和&nbsp;<code>number</code>&nbsp;的共有属性是没问题的:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">getString<span class="token punctuation">(something<span class="token operator">: <span class="token builtin">string <span class="token operator">| <span class="token builtin">number<span class="token punctuation">)<span class="token operator">: <span class="token builtin">string <span class="token punctuation">{
    <span class="token keyword">return something<span class="token punctuation">.<span class="token function">toString<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let myFavoriteNumber<span class="token operator">: <span class="token builtin">string <span class="token operator">| <span class="token builtin">number<span class="token punctuation">;
myFavoriteNumber <span class="token operator">= <span class="token string">'seven'<span class="token punctuation">;
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(myFavoriteNumber<span class="token punctuation">.length<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// 5
myFavoriteNumber <span class="token operator">= <span class="token number">7<span class="token punctuation">;
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(myFavoriteNumber<span class="token punctuation">.length<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// 编译时报错

<span class="token comment">// index.ts(5,30): error TS2339: Property 'length' does not exist on type 'number'.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上例中,第二行的&nbsp;<code>myFavoriteNumber</code>&nbsp;被推断成了&nbsp;<code>string</code>,访问它的&nbsp;<code>length</code>&nbsp;属性不会报错。</p>
<p>而第四行的&nbsp;<code>myFavoriteNumber</code>&nbsp;被推断成了&nbsp;<code>number</code>,访问它的&nbsp;<code>length</code>&nbsp;属性时就报错了。</p>
<div class="cnblogs_code">
<pre>let a:string | number | <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)">;

a</span>="hello"<span style="color: rgba(0, 0, 0, 1)">;
a</span>=<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
a</span>=666<span style="color: rgba(0, 0, 0, 1)">;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">a={};//错误,对象类型</span>
<span style="color: rgba(0, 0, 0, 1)">
console.log(</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> a);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">number</span>

<span style="color: rgba(0, 0, 255, 1)">function</span> f1(c:string|number){<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">函数的参数可以是联合类型</span>
<span style="color: rgba(0, 0, 0, 1)">}

f1(</span>100<span style="color: rgba(0, 0, 0, 1)">);
f1(</span>"abc");</pre>
</div>
<h1>六、对象的类型——接口</h1>
<p>在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。</p>
<h2 id="%E4%BB%80%E4%B9%88%E6%98%AF%E6%8E%A5%E5%8F%A3">6.1、什么是接口<br></h2>
<p>在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。</p>
<p>TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。</p>
<h2 id="%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%8B%E5%AD%90">6.2、简单的例子<br></h2>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Person <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    age<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let tom<span class="token operator">: Person <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'Tom'<span class="token punctuation">,
    age<span class="token operator">: <span class="token number">25
<span class="token punctuation">}<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上面的例子中,我们定义了一个接口&nbsp;<code>Person</code>,接着定义了一个变量&nbsp;<code>tom</code>,它的类型是&nbsp;<code>Person</code>。这样,我们就约束了&nbsp;<code>tom</code>&nbsp;的形状必须和接口&nbsp;<code>Person</code>&nbsp;一致。</p>
<p>接口一般首字母大写。有的编程语言中会建议接口的名称加上&nbsp;<code>I</code>&nbsp;前缀。</p>
<p>定义的变量比接口少了一些属性是不允许的:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Person <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    age<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let tom<span class="token operator">: Person <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'Tom'
<span class="token punctuation">}<span class="token punctuation">;

<span class="token comment">// index.ts(6,5): error TS2322: Type '{ name: string; }' is not assignable to type 'Person'.
<span class="token comment">//   Property 'age' is missing in type '{ name: string; }'.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>多一些属性也是不允许的:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Person <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    age<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let tom<span class="token operator">: Person <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'Tom'<span class="token punctuation">,
    age<span class="token operator">: <span class="token number">25<span class="token punctuation">,
    gender<span class="token operator">: <span class="token string">'male'
<span class="token punctuation">}<span class="token punctuation">;

<span class="token comment">// index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
<span class="token comment">//   Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>可见,赋值的时候,变量的形状必须和接口的形状保持一致。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">接口 interface 接口是一种抽象类型 接口中的属性不能有初值,方法不能有方法体</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)">定义接口人</span>
<span style="color: rgba(0, 0, 0, 1)">interface IPerson{
    name:string;
    age:number;
    hello():</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">;
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">约束对象</span>
let tom:IPerson=<span style="color: rgba(0, 0, 0, 1)">{
    name:</span>"汤姆"<span style="color: rgba(0, 0, 0, 1)">,
    age:</span>18<span style="color: rgba(0, 0, 0, 1)">,
    hello(){
      console.log(</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name+","+<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.age);
    }
};
tom.hello();

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">约束类的属性与行为</span>
<span style="color: rgba(0, 0, 0, 1)">class Student implements IPerson{
    name: string;
    age: number;
    sex:string;
    constructor(name:string, age:number,sex:string){</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">构造函数</span>
      <span style="color: rgba(0, 0, 255, 1)">this</span>.name=<span style="color: rgba(0, 0, 0, 1)">name;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.age=<span style="color: rgba(0, 0, 0, 1)">age;
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sex=<span style="color: rgba(0, 0, 0, 1)">sex;
    }
    hello (): </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> {
      console.log(</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name+","+<span style="color: rgba(0, 0, 255, 1)">this</span>.age+","+<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.sex);
    }
}

let jack</span>=<span style="color: rgba(0, 0, 255, 1)">new</span> Student("jack",19,"男"<span style="color: rgba(0, 0, 0, 1)">);
jack.hello();</span></pre>
</div>
<h2 id="%E5%8F%AF%E9%80%89%E5%B1%9E%E6%80%A7">6.3、可选属性<br></h2>
<p>有时我们希望不要完全匹配一个形状,那么可以用可选属性:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Person <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    age<span class="token operator">?<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let tom<span class="token operator">: Person <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'Tom'
<span class="token punctuation">}<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Person <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    age<span class="token operator">?<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let tom<span class="token operator">: Person <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'Tom'<span class="token punctuation">,
    age<span class="token operator">: <span class="token number">25
<span class="token punctuation">}<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>可选属性的含义是该属性可以不存在。</p>
<p>这时仍然不允许添加未定义的属性:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Person <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    age<span class="token operator">?<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let tom<span class="token operator">: Person <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'Tom'<span class="token punctuation">,
    age<span class="token operator">: <span class="token number">25<span class="token punctuation">,
    gender<span class="token operator">: <span class="token string">'male'
<span class="token punctuation">}<span class="token punctuation">;

<span class="token comment">// examples/playground/index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
<span class="token comment">//   Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.<br><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface IPerson{
    name:string;
    age</span>?:number;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">?号表示该属性是可选的,对象中可以不包含</span>
    hi?():<span style="color: rgba(0, 0, 255, 1)">void</span>;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">可选方法</span>
    hello?:(a:number,b:number)=&gt;<span style="color: rgba(0, 0, 255, 1)">boolean</span>;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方法名:(参数)=&gt; 返回值</span>
<span style="color: rgba(0, 0, 0, 1)">}

let tom:IPerson</span>=<span style="color: rgba(0, 0, 0, 1)">{
    name: </span>"Tom"<span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<h2 id="%E4%BB%BB%E6%84%8F%E5%B1%9E%E6%80%A7">6.4、任意属性<br></h2>
<p>有时候我们希望一个接口允许有任意的属性,可以使用如下方式:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Person <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    age<span class="token operator">?<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    <span class="token punctuation"><span class="token operator">: <span class="token builtin">any<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let tom<span class="token operator">: Person <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'Tom'<span class="token punctuation">,
    gender<span class="token operator">: <span class="token string">'male'
<span class="token punctuation">}<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>使用&nbsp;<code></code>&nbsp;定义了任意属性取&nbsp;<code>string</code>&nbsp;类型的值。</p>
<p>需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Person <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    age<span class="token operator">?<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    <span class="token punctuation"><span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let tom<span class="token operator">: Person <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'Tom'<span class="token punctuation">,
    age<span class="token operator">: <span class="token number">25<span class="token punctuation">,
    gender<span class="token operator">: <span class="token string">'male'
<span class="token punctuation">}<span class="token punctuation">;

<span class="token comment">// index.ts(3,5): error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'.
<span class="token comment">// index.ts(7,5): error TS2322: Type '{ : string | number; name: string; age: number; gender: string; }' is not assignable to type 'Person'.
<span class="token comment">//   Index signatures are incompatible.
<span class="token comment">//   Type 'string | number' is not assignable to type 'string'.
<span class="token comment">//       Type 'number' is not assignable to type 'string'.<br><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface IPerson{
    id: number;
    name: string;
    age: number;
    :any;</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义一个名称为string类型的任意属性,prop可以更换成其它名称</span>
<span style="color: rgba(0, 0, 0, 1)">}

let tom:IPerson</span>=<span style="color: rgba(0, 0, 0, 1)">{
    id: </span>1<span style="color: rgba(0, 0, 0, 1)">,
    name: </span>"Tom"<span style="color: rgba(0, 0, 0, 1)">,
    age: </span>20<span style="color: rgba(0, 0, 0, 1)">,
    a:</span>1<span style="color: rgba(0, 0, 0, 1)">,
    b:</span>2<span style="color: rgba(0, 0, 0, 1)">
};</span></pre>
</div>
<p>上例中,任意属性的值允许是&nbsp;<code>string</code>,但是可选属性&nbsp;<code>age</code>&nbsp;的值却是&nbsp;<code>number</code>,<code>number</code>&nbsp;不是&nbsp;<code>string</code>&nbsp;的子属性,所以报错了。</p>
<p>另外,在报错信息中可以看出,此时&nbsp;<code>{ name: 'Tom', age: 25, gender: 'male' }</code>&nbsp;的类型被推断成了&nbsp;<code>{ : string | number; name: string; age: number; gender: string; }</code>,这是联合类型和接口的结合。</p>
<p>一个接口中只能定义一个任意属性。如果接口中有多个类型的属性,则可以在任意属性中使用联合类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Person <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    age<span class="token operator">?<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    <span class="token punctuation"><span class="token operator">: <span class="token builtin">string <span class="token operator">| <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let tom<span class="token operator">: Person <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'Tom'<span class="token punctuation">,
    age<span class="token operator">: <span class="token number">25<span class="token punctuation">,
    gender<span class="token operator">: <span class="token string">'male'
<span class="token punctuation">}<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 id="%E5%8F%AA%E8%AF%BB%E5%B1%9E%E6%80%A7">6.5、只读属性<br></h2>
<p>有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用&nbsp;<code>readonly</code>&nbsp;定义只读属性:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Person <span class="token punctuation">{
    <span class="token keyword">readonly id<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    age<span class="token operator">?<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    <span class="token punctuation"><span class="token operator">: <span class="token builtin">any<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let tom<span class="token operator">: Person <span class="token operator">= <span class="token punctuation">{
    id<span class="token operator">: <span class="token number">89757<span class="token punctuation">,
    name<span class="token operator">: <span class="token string">'Tom'<span class="token punctuation">,
    gender<span class="token operator">: <span class="token string">'male'
<span class="token punctuation">}<span class="token punctuation">;

tom<span class="token punctuation">.id <span class="token operator">= <span class="token number">9527<span class="token punctuation">;

<span class="token comment">// index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上例中,使用&nbsp;<code>readonly</code>&nbsp;定义的属性&nbsp;<code>id</code>&nbsp;初始化后,又被赋值了,所以报错了。</p>
<p>注意,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Person <span class="token punctuation">{
    <span class="token keyword">readonly id<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    age<span class="token operator">?<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    <span class="token punctuation"><span class="token operator">: <span class="token builtin">any<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let tom<span class="token operator">: Person <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'Tom'<span class="token punctuation">,
    gender<span class="token operator">: <span class="token string">'male'
<span class="token punctuation">}<span class="token punctuation">;

tom<span class="token punctuation">.id <span class="token operator">= <span class="token number">89757<span class="token punctuation">;

<span class="token comment">// index.ts(8,5): error TS2322: Type '{ name: string; gender: string; }' is not assignable to type 'Person'.
<span class="token comment">//   Property 'id' is missing in type '{ name: string; gender: string; }'.
<span class="token comment">// index.ts(13,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上例中,报错信息有两处,第一处是在对&nbsp;<code>tom</code>&nbsp;进行赋值的时候,没有给&nbsp;<code>id</code>&nbsp;赋值。</p>
<p>第二处是在给&nbsp;<code>tom.id</code>&nbsp;赋值的时候,由于它是只读属性,所以报错了。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface IPerson{
    readonly id</span>?: number;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">id是只读的</span>
<span style="color: rgba(0, 0, 0, 1)">    name: string;
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">只读属性的值只能在对象中初始化一次后就不允许修改</span>
let tom:IPerson=<span style="color: rgba(0, 0, 0, 1)">{
    id: </span>1<span style="color: rgba(0, 0, 0, 1)">,
    name: </span>"Tom"<span style="color: rgba(0, 0, 0, 1)">
};

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">tom.id=-100;//错误,不允许修改</span></pre>
</div>
<h2>6.6、方法</h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface IPerson {
    firstName:string,
    lastName:string,
    sayHi: ()</span>=&gt;<span style="color: rgba(0, 0, 0, 1)">string
}

</span><span style="color: rgba(0, 0, 255, 1)">var</span> customer:IPerson =<span style="color: rgba(0, 0, 0, 1)"> {
    firstName:</span>"Tom"<span style="color: rgba(0, 0, 0, 1)">,
    lastName:</span>"Hanks"<span style="color: rgba(0, 0, 0, 1)">,
    sayHi: ():string </span>=&gt;{<span style="color: rgba(0, 0, 255, 1)">return</span> "Hi there"<span style="color: rgba(0, 0, 0, 1)">}
}

console.log(</span>"Customer 对象 "<span style="color: rgba(0, 0, 0, 1)">);
console.log(customer.firstName);
console.log(customer.lastName);
console.log(customer.sayHi());</span></pre>
</div>
<p>在接口中定义了方法sayHi,要求返回值为String类型。</p>
<p>运行结果:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">Customer 对象
Tom
Hanks
Hi there</span></pre>
</div>
<p>编译以后的代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> customer =<span style="color: rgba(0, 0, 0, 1)"> {
    firstName: </span>"Tom"<span style="color: rgba(0, 0, 0, 1)">,
    lastName: </span>"Hanks"<span style="color: rgba(0, 0, 0, 1)">,
    sayHi: </span><span style="color: rgba(0, 0, 255, 1)">function</span> () { <span style="color: rgba(0, 0, 255, 1)">return</span> "Hi there"<span style="color: rgba(0, 0, 0, 1)">; }
};
console.log(</span>"Customer 对象 "<span style="color: rgba(0, 0, 0, 1)">);
console.log(customer.firstName);
console.log(customer.lastName);
console.log(customer.sayHi());</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface ICar{
    name:string;
    readonly run:(speed:number)</span>=&gt;<span style="color: rgba(0, 0, 255, 1)">void</span>;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">run方法,(speed:number)约束参数,void是返回值</span>
    stop():string; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方法名stop参数():返回值string</span>
<span style="color: rgba(0, 0, 0, 1)">    a:Function;
}

let car:ICar</span>=<span style="color: rgba(0, 0, 0, 1)">{
    name: </span>"BYD"<span style="color: rgba(0, 0, 0, 1)">,
    run: </span><span style="color: rgba(0, 0, 255, 1)">function</span> (speed: number): <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> {
      console.log(`${</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name}以${speed}km/s的速度在运行`);
<span style="color: rgba(0, 0, 0, 1)">    },
    stop: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (): string {
       </span><span style="color: rgba(0, 0, 255, 1)">return</span> "车停了"<span style="color: rgba(0, 0, 0, 1)">;
    },
    a:()</span>=&gt;1<span style="color: rgba(0, 0, 0, 1)">
}

car.run(</span>100);</pre>
</div>
<h2>6.7、联合类型和接口</h2>
<p>以下实例演示了如何在接口中使用联合类型:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface RunOptions {
    program:string;
    commandline:string[]</span>|string|(()=&gt;<span style="color: rgba(0, 0, 0, 1)">string);
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> commandline 是字符串</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> options:RunOptions = {program:"test1",commandline:"Hello"<span style="color: rgba(0, 0, 0, 1)">};
console.log(options.commandline)

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> commandline 是字符串数组</span>
options = {program:"test1",commandline:["Hello","World"<span style="color: rgba(0, 0, 0, 1)">]};
console.log(options.commandline[</span>0<span style="color: rgba(0, 0, 0, 1)">]);
console.log(options.commandline[</span>1<span style="color: rgba(0, 0, 0, 1)">]);

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> commandline 是一个函数表达式</span>
options = {program:"test1",commandline:()=&gt;{<span style="color: rgba(0, 0, 255, 1)">return</span> "**Hello World**"<span style="color: rgba(0, 0, 0, 1)">;}};

</span><span style="color: rgba(0, 0, 255, 1)">var</span> fn:any =<span style="color: rgba(0, 0, 0, 1)"> options.commandline;
console.log(fn());</span></pre>
</div>
<p>编译以上代码,得到以下 JavaScript 代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> commandline 是字符串</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> options = { program: "test1", commandline: "Hello"<span style="color: rgba(0, 0, 0, 1)"> };
console.log(options.commandline);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> commandline 是字符串数组</span>
options = { program: "test1", commandline: ["Hello", "World"<span style="color: rgba(0, 0, 0, 1)">] };
console.log(options.commandline[</span>0<span style="color: rgba(0, 0, 0, 1)">]);
console.log(options.commandline[</span>1<span style="color: rgba(0, 0, 0, 1)">]);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> commandline 是一个函数表达式</span>
options = { program: "test1", commandline: <span style="color: rgba(0, 0, 255, 1)">function</span> () { <span style="color: rgba(0, 0, 255, 1)">return</span> "**Hello World**"<span style="color: rgba(0, 0, 0, 1)">; } };
</span><span style="color: rgba(0, 0, 255, 1)">var</span> fn =<span style="color: rgba(0, 0, 0, 1)"> options.commandline;
console.log(fn());</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface IOption{
    command:string[]</span>|string|(()=&gt;<span style="color: rgba(0, 0, 0, 1)">string)
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">string[] string类型的数组</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">string 字符</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">(()=&gt;string) 没有参数但返回string类型的函数</span>
<span style="color: rgba(0, 0, 0, 1)">}

let o1</span>=<span style="color: rgba(0, 0, 0, 1)">{
    command:[</span>"cd","dir"<span style="color: rgba(0, 0, 0, 1)">]
}

let o2</span>=<span style="color: rgba(0, 0, 0, 1)">{
    command:</span>"cls"<span style="color: rgba(0, 0, 0, 1)">
}

let o3</span>=<span style="color: rgba(0, 0, 0, 1)">{
    command:()</span>=&gt;"exit"<span style="color: rgba(0, 0, 0, 1)">
}

let o4</span>=<span style="color: rgba(0, 0, 0, 1)">{
    command:()</span>=&gt;{<span style="color: rgba(0, 0, 255, 1)">return</span> "exit"<span style="color: rgba(0, 0, 0, 1)">;}
}

let o5</span>=<span style="color: rgba(0, 0, 0, 1)">{
    command:</span><span style="color: rgba(0, 0, 255, 1)">function</span>(){<span style="color: rgba(0, 0, 255, 1)">return</span> "exit"<span style="color: rgba(0, 0, 0, 1)">;}
}</span></pre>
</div>
<h2>6.8、接口和数组</h2>
<p>接口中我们可以将数组的索引值和元素设置为不同类型,索引值可以是数字或字符串。</p>
<p>设置元素为字符串类型:</p>
<p>示例1:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface namelist {
    :string
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 类型一致,正确</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> list2:namelist = ["Google","Runoob","Taobao"<span style="color: rgba(0, 0, 0, 1)">]
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 错误元素 1 不是 string 类型</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> var list2:namelist = ["Runoob",1,"Taobao"]</span></pre>
</div>
<p>示例2:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface ages {
    :number
}

</span><span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> agelist:ages;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 类型正确 </span>
agelist["runoob"] = 15

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 类型错误,输出error TS2322: Type '"google"' is not assignable to type 'number'.</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> agelist = "google"</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface INameList{
    :string
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">约束的对象只能使用数字索引访问数组,数组中的值只能是string类型</span>
<span style="color: rgba(0, 0, 0, 1)">}

let users:INameList</span>=["tom","jack","rose"<span style="color: rgba(0, 0, 0, 1)">];
console.log(users[</span>1]);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">jack</span>
<span style="color: rgba(0, 0, 0, 1)">
interface INameList2{
    :number
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">约束的对象只能使用key方法,对象中属性的值只能是number类型</span>
<span style="color: rgba(0, 0, 0, 1)">}

let users2:INameList2</span>=<span style="color: rgba(0, 0, 0, 1)">{
    </span>"tom":202201<span style="color: rgba(0, 0, 0, 1)">,
    </span>"jack":202202<span style="color: rgba(0, 0, 0, 1)">,
    </span>"rose":202203<span style="color: rgba(0, 0, 0, 1)">
}
console.log(users2[</span>"jack"]);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">jack</span></pre>
</div>
<h2>6.9、接口继承</h2>
<p>接口继承就是说接口可以通过其他接口来扩展自己。</p>
<p>Typescript 允许接口继承多个接口。</p>
<p>继承使用关键字&nbsp;<span class="marked">extends。</span></p>
<p>单接口继承语法格式:</p>
<pre class="prettyprint prettyprinted"><span class="typ">Child_interface_name<span class="pln"> <span class="kwd">extends<span class="pln"> super_interface_name</span></span></span></span></pre>
<p>多接口继承语法格式:</p>
<pre class="prettyprint prettyprinted"><span class="typ">Child_interface_name<span class="pln"> <span class="kwd">extends<span class="pln"> super_interface1_name<span class="pun">,<span class="pln"> super_interface2_name<span class="pun">,…,<span class="pln">super_interfaceN_name<br>继承的各个接口使用逗号&nbsp;<span class="marked">,&nbsp;分隔。</span><br></span></span></span></span></span></span></span></span></pre>
<p>单继承实例</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface Person {
   age:number
}

interface Musician extends Person {
   instrument:string
}

</span><span style="color: rgba(0, 0, 255, 1)">var</span> drummer = &lt;Musician&gt;<span style="color: rgba(0, 0, 0, 1)">{};
drummer.age </span>= 27<span style="color: rgba(0, 0, 0, 1)">
drummer.instrument </span>= "Drums"<span style="color: rgba(0, 0, 0, 1)">
console.log(</span>"年龄:"+<span style="color: rgba(0, 0, 0, 1)">drummer.age)
console.log(</span>"喜欢的乐器:"+drummer.instrument)</pre>
</div>
<p>输出结果为:</p>
<pre class="prettyprint prettyprinted"><span class="pun">年龄:<span class="pln"><span class="lit">27<span class="pln">
<span class="pun">喜欢的乐器:<span class="pln"><span class="typ">Drums</span></span></span></span></span></span></span></pre>
<p>多继承实例</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface IParent1 {
    v1:number
}

interface IParent2 {
    v2:number
}

interface Child extends IParent1, IParent2 { }
</span><span style="color: rgba(0, 0, 255, 1)">var</span> Iobj:Child = { v1:12, v2:23<span style="color: rgba(0, 0, 0, 1)">}
console.log(</span>"value 1: "+Iobj.v1+" value 2: "+Iobj.v2)</pre>
</div>
<p>输出结果为:</p>
<pre class="prettyprint prettyprinted"><span class="pln">value <span class="lit">1<span class="pun">:<span class="pln"> <span class="lit">12<span class="pln"> value <span class="lit">2<span class="pun">:<span class="pln"> <span class="lit">23<br></span></span></span></span></span></span></span></span></span></span></pre>
<h2>6.10、匿名类型</h2>
<p>可以为对象指定一个匿名类型,如下所示:</p>
<div class="cnblogs_code">
<pre>let obje:{a:string,b:number}={a:"a",b:1};</pre>
</div>
<div class="cnblogs_code">
<pre>type Person={<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">类型</span>
<span style="color: rgba(0, 0, 0, 1)">    name:string,
    age</span>?<span style="color: rgba(0, 0, 0, 1)">:number
}

let obj:{name:string,age</span>?:number}={<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">匿名类型</span>
    name:"jack"<span style="color: rgba(0, 0, 0, 1)">
};

let tom:Person</span>=<span style="color: rgba(0, 0, 0, 1)">{
    name:</span>"tom"<span style="color: rgba(0, 0, 0, 1)">,
    age:</span>100<span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<p>&nbsp;</p>
<h1>七、数组的类型</h1>
<p>在 TypeScript 中,数组类型有多种定义方式,比较灵活。</p>
<h2 id="%E7%B1%BB%E5%9E%8B--%E6%96%B9%E6%8B%AC%E5%8F%B7%E8%A1%A8%E7%A4%BA%E6%B3%95">7.1、「类型 + 方括号」表示法<br></h2>
<p>最简单的方法是使用「类型 + 方括号」来表示数组:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let fibonacci<span class="token operator">: <span class="token builtin">number<span class="token punctuation">[<span class="token punctuation">] <span class="token operator">= <span class="token punctuation">[<span class="token number">1<span class="token punctuation">, <span class="token number">1<span class="token punctuation">, <span class="token number">2<span class="token punctuation">, <span class="token number">3<span class="token punctuation">, <span class="token number">5<span class="token punctuation">]<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>数组的项中不允许出现其他的类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let fibonacci<span class="token operator">: <span class="token builtin">number<span class="token punctuation">[<span class="token punctuation">] <span class="token operator">= <span class="token punctuation">[<span class="token number">1<span class="token punctuation">, <span class="token string">'1'<span class="token punctuation">, <span class="token number">2<span class="token punctuation">, <span class="token number">3<span class="token punctuation">, <span class="token number">5<span class="token punctuation">]<span class="token punctuation">;

<span class="token comment">// Type 'string' is not assignable to type 'number'.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>数组的一些方法的参数也会根据数组在定义时约定的类型进行限制:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let fibonacci<span class="token operator">: <span class="token builtin">number<span class="token punctuation">[<span class="token punctuation">] <span class="token operator">= <span class="token punctuation">[<span class="token number">1<span class="token punctuation">, <span class="token number">1<span class="token punctuation">, <span class="token number">2<span class="token punctuation">, <span class="token number">3<span class="token punctuation">, <span class="token number">5<span class="token punctuation">]<span class="token punctuation">;
fibonacci<span class="token punctuation">.<span class="token function">push<span class="token punctuation">(<span class="token string">'8'<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// Argument of type '"8"' is not assignable to parameter of type 'number'.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上例中,<code>push</code>&nbsp;方法只允许传入&nbsp;<code>number</code>&nbsp;类型的参数,但是却传了一个&nbsp;<code>"8"</code>&nbsp;类型的参数,所以报错了。这里&nbsp;<code>"8"</code>&nbsp;是一个字符串字面量类型,会在后续章节中详细介绍。</p>
<h2 id="%E6%95%B0%E7%BB%84%E6%B3%9B%E5%9E%8B">7.2、数组泛型<br></h2>
<p>我们也可以使用数组泛型(Array Generic)&nbsp;<code>Array&lt;elemType&gt;</code>&nbsp;来表示数组:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let fibonacci<span class="token operator">: <span class="token builtin">Array<span class="token operator">&lt;<span class="token builtin">number<span class="token operator">&gt; <span class="token operator">= <span class="token punctuation">[<span class="token number">1<span class="token punctuation">, <span class="token number">1<span class="token punctuation">, <span class="token number">2<span class="token punctuation">, <span class="token number">3<span class="token punctuation">, <span class="token number">5<span class="token punctuation">]<span class="token punctuation">;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 id="%E7%94%A8%E6%8E%A5%E5%8F%A3%E8%A1%A8%E7%A4%BA%E6%95%B0%E7%BB%84">7.3、用接口表示数组<br></h2>
<p>接口也可以用来描述数组:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">NumberArray <span class="token punctuation">{
    <span class="token punctuation"><span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">let fibonacci<span class="token operator">: NumberArray <span class="token operator">= <span class="token punctuation">[<span class="token number">1<span class="token punctuation">, <span class="token number">1<span class="token punctuation">, <span class="token number">2<span class="token punctuation">, <span class="token number">3<span class="token punctuation">, <span class="token number">5<span class="token punctuation">]<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p><code>NumberArray</code>&nbsp;表示:只要索引的类型是数字时,那么值的类型必须是数字。</p>
<p>虽然接口也可以用来描述数组,但是我们一般不会这么做,因为这种方式比前两种方式复杂多了。</p>
<p>不过有一种情况例外,那就是它常用来表示类数组。</p>
<h2 id="%E7%B1%BB%E6%95%B0%E7%BB%84">7.4、类数组<br></h2>
<p>类数组(Array-like Object)不是数组类型,比如&nbsp;<code>arguments</code>:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">sum<span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">let args<span class="token operator">: <span class="token builtin">number<span class="token punctuation">[<span class="token punctuation">] <span class="token operator">= arguments<span class="token punctuation">;
<span class="token punctuation">}

<span class="token comment">// Type 'IArguments' is missing the following properties from type 'number[]': pop, push, concat, join, and 24 more.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上例中,<code>arguments</code>&nbsp;实际上是一个类数组,不能用普通的数组的方式来描述,而应该用接口:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">sum<span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">let args<span class="token operator">: <span class="token punctuation">{
      <span class="token punctuation"><span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
      length<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
      callee<span class="token operator">: <span class="token builtin">Function<span class="token punctuation">;
    <span class="token punctuation">} <span class="token operator">= arguments<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>在这个例子中,我们除了约束当索引的类型是数字时,值的类型必须是数字之外,也约束了它还有&nbsp;<code>length</code>&nbsp;和&nbsp;<code>callee</code>&nbsp;两个属性。</p>
<p>事实上常用的类数组都有自己的接口定义,如&nbsp;<code>IArguments</code>,&nbsp;<code>NodeList</code>,&nbsp;<code>HTMLCollection</code>&nbsp;等:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">sum<span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">let args<span class="token operator">: IArguments <span class="token operator">= arguments<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></code></pre>
<p>其中&nbsp;<code>IArguments</code>&nbsp;是 TypeScript 中定义好了的类型,它实际上就是:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">IArguments <span class="token punctuation">{
    <span class="token punctuation"><span class="token operator">: <span class="token builtin">any<span class="token punctuation">;
    length<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    callee<span class="token operator">: <span class="token builtin">Function<span class="token punctuation">;
<span class="token punctuation">}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 id="any-%E5%9C%A8%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8">7.5、any 在数组中的应用<br></h2>
<p>一个比较常见的做法是,用&nbsp;<code>any</code>&nbsp;表示数组中允许出现任意类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let list<span class="token operator">: <span class="token builtin">any<span class="token punctuation">[<span class="token punctuation">] <span class="token operator">= <span class="token punctuation">[<span class="token string">'xcatliu'<span class="token punctuation">, <span class="token number">25<span class="token punctuation">, <span class="token punctuation">{ website<span class="token operator">: <span class="token string">'http://abc.com' <span class="token punctuation">}<span class="token punctuation">]<span class="token punctuation">;</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h1>八、函数的类型</h1>
<h2 id="%E5%87%BD%E6%95%B0%E5%A3%B0%E6%98%8E">8.1、函数声明<br></h2>
<p>在 JavaScript 中,有两种常见的定义函数的方式——函数声明(Function Declaration)和函数表达式(Function Expression):</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// 函数声明(Function Declaration)
<span class="token keyword">function <span class="token function">sum<span class="token punctuation">(<span class="token parameter">x<span class="token punctuation">, y<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword control-flow">return x <span class="token operator">+ y<span class="token punctuation">;
<span class="token punctuation">}

<span class="token comment">// 函数表达式(Function Expression)
<span class="token keyword">let <span class="token function-variable function">mySum <span class="token operator">= <span class="token keyword">function <span class="token punctuation">(<span class="token parameter">x<span class="token punctuation">, y<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword control-flow">return x <span class="token operator">+ y<span class="token punctuation">;
<span class="token punctuation">}<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到,其中函数声明的类型定义较简单:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">sum<span class="token punctuation">(x<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, y<span class="token operator">: <span class="token builtin">number<span class="token punctuation">)<span class="token operator">: <span class="token builtin">number <span class="token punctuation">{
    <span class="token keyword">return x <span class="token operator">+ y<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>注意,输入多余的(或者少于要求的)参数,是不被允许的:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">sum<span class="token punctuation">(x<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, y<span class="token operator">: <span class="token builtin">number<span class="token punctuation">)<span class="token operator">: <span class="token builtin">number <span class="token punctuation">{
    <span class="token keyword">return x <span class="token operator">+ y<span class="token punctuation">;
<span class="token punctuation">}
<span class="token function">sum<span class="token punctuation">(<span class="token number">1<span class="token punctuation">, <span class="token number">2<span class="token punctuation">, <span class="token number">3<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">sum<span class="token punctuation">(x<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, y<span class="token operator">: <span class="token builtin">number<span class="token punctuation">)<span class="token operator">: <span class="token builtin">number <span class="token punctuation">{
    <span class="token keyword">return x <span class="token operator">+ y<span class="token punctuation">;
<span class="token punctuation">}
<span class="token function">sum<span class="token punctuation">(<span class="token number">1<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 id="%E5%87%BD%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F">8.2、函数表达式<br></h2>
<p>如果要我们现在写一个对函数表达式(Function Expression)的定义,可能会写成这样:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let <span class="token function-variable function">mySum <span class="token operator">= <span class="token keyword">function <span class="token punctuation">(x<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, y<span class="token operator">: <span class="token builtin">number<span class="token punctuation">)<span class="token operator">: <span class="token builtin">number <span class="token punctuation">{
    <span class="token keyword">return x <span class="token operator">+ y<span class="token punctuation">;
<span class="token punctuation">}<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>这是可以通过编译的,不过事实上,上面的代码只对等号右侧的匿名函数进行了类型定义,而等号左边的&nbsp;<code>mySum</code>,是通过赋值操作进行类型推论而推断出来的。如果需要我们手动给&nbsp;<code>mySum</code>&nbsp;添加类型,则应该是这样:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let <span class="token function-variable function">mySum<span class="token operator">: <span class="token punctuation">(x<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, y<span class="token operator">: <span class="token builtin">number<span class="token punctuation">) <span class="token operator">=&gt; <span class="token function-variable function">number <span class="token operator">= <span class="token keyword">function <span class="token punctuation">(x<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, y<span class="token operator">: <span class="token builtin">number<span class="token punctuation">)<span class="token operator">: <span class="token builtin">number <span class="token punctuation">{
    <span class="token keyword">return x <span class="token operator">+ y<span class="token punctuation">;
<span class="token punctuation">}<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>注意不要混淆了 TypeScript 中的&nbsp;<code>=&gt;</code>&nbsp;和 ES6 中的&nbsp;<code>=&gt;</code>。</p>
<p>在 TypeScript 的类型定义中,<code>=&gt;</code>&nbsp;用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。</p>
<p>在 ES6 中,<code>=&gt;</code>&nbsp;叫做箭头函数,应用十分广泛,可以参考&nbsp;ES6 中的箭头函数。</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword"><span class="token function-variable function">mySum<span class="token operator">: <span class="token punctuation">(x<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, y<span class="token operator">: <span class="token builtin">number<span class="token punctuation">) <span class="token operator">=&gt; <span class="token function-variable function">number 是对函数类型(形状)的约束<br></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<pre class="language-ts"><code class="language-ts"><span class="token keyword"><span class="token function-variable function"><span class="token operator"><span class="token punctuation"><span class="token operator"><span class="token builtin"><span class="token punctuation"><span class="token operator"><span class="token builtin"><span class="token punctuation"><span class="token operator"><span class="token function-variable function"><span class="token operator"><span class="token keyword">function <span class="token punctuation">(x<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, y<span class="token operator">: <span class="token builtin">number<span class="token punctuation">)<span class="token operator">: <span class="token builtin">number是对函数约束的实现<br><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<div class="cnblogs_code">
<pre>let sum=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(a:number,b:number):number{
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> a+<span style="color: rgba(0, 0, 0, 1)">b;
}

let sub</span>=(a,b)=&gt;a-<span style="color: rgba(0, 0, 0, 1)">b;

let add</span>=(a,b)=&gt;a+<span style="color: rgba(0, 0, 0, 1)">b;

let myfun:(x:number,y:number)</span>=&gt;<span style="color: rgba(0, 0, 0, 1)">number;

myfun</span>=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(a:number,b:number):number{
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> a+<span style="color: rgba(0, 0, 0, 1)">b;
}</span></pre>
</div>
<h2 id="%E7%94%A8%E6%8E%A5%E5%8F%A3%E5%AE%9A%E4%B9%89%E5%87%BD%E6%95%B0%E7%9A%84%E5%BD%A2%E7%8A%B6">8.3、用接口定义函数的形状<br></h2>
<p>我们也可以使用接口的方式来定义一个函数需要符合的形状:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">SearchFunc <span class="token punctuation">{
    <span class="token punctuation">(source<span class="token operator">: <span class="token builtin">string<span class="token punctuation">, subString<span class="token operator">: <span class="token builtin">string<span class="token punctuation">)<span class="token operator">: <span class="token builtin">boolean<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let mySearch<span class="token operator">: SearchFunc<span class="token punctuation">;
<span class="token function-variable function">mySearch <span class="token operator">= <span class="token keyword">function<span class="token punctuation">(source<span class="token operator">: <span class="token builtin">string<span class="token punctuation">, subString<span class="token operator">: <span class="token builtin">string<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">return source<span class="token punctuation">.<span class="token function">search<span class="token punctuation">(subString<span class="token punctuation">) <span class="token operator">!== <span class="token operator">-<span class="token number">1<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>采用函数表达式|接口定义函数的方式时,对等号左侧进行类型限制,可以保证以后对函数名赋值时保证参数个数、参数类型、返回值类型不变。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface IA{
    a:number
}

let x:IA</span>={a:100};<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">约束对象</span>
let z:{b:number}={b:200<span style="color: rgba(0, 0, 0, 1)">};

class Foo implements IA {</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">约束类</span>
<span style="color: rgba(0, 0, 0, 1)">    a: number;
}

interface IUsernames{
    :string;
}

let usernames:IUsernames</span>=["foo", "bar", "baz"];<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">约束数组</span>
<span style="color: rgba(0, 0, 0, 1)">
interface ISearchFun{
    (location:string,keyword:string):</span><span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)">;
}
let searchFun:ISearchFun;
searchFun</span>=(a,b)=&gt;{<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">约束函数</span>
    <span style="color: rgba(0, 0, 255, 1)">return</span> a==<span style="color: rgba(0, 0, 0, 1)">b;
}

let sum:(a:number,b:number)</span>=&gt;<span style="color: rgba(0, 0, 0, 1)">number;

sum</span>=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(x:number,y:number):number{
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> x+<span style="color: rgba(0, 0, 0, 1)">y;
}

let mysum:(a:number,b:number)</span>=&gt;number=<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(x,y){
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> x+<span style="color: rgba(0, 0, 0, 1)">y;
}</span></pre>
</div>
<h2 id="%E5%8F%AF%E9%80%89%E5%8F%82%E6%95%B0">8.4、可选参数<br></h2>
<p>前面提到,输入多余的(或者少于要求的)参数,是不允许的。那么如何定义可选的参数呢?</p>
<p>与接口中的可选属性类似,我们用&nbsp;<code>?</code>&nbsp;表示可选的参数:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">buildName<span class="token punctuation">(firstName<span class="token operator">: <span class="token builtin">string<span class="token punctuation">, lastName<span class="token operator">?<span class="token operator">: <span class="token builtin">string<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">if <span class="token punctuation">(lastName<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">return firstName <span class="token operator">+ <span class="token string">' ' <span class="token operator">+ lastName<span class="token punctuation">;
    <span class="token punctuation">} <span class="token keyword">else <span class="token punctuation">{
      <span class="token keyword">return firstName<span class="token punctuation">;
    <span class="token punctuation">}
<span class="token punctuation">}
<span class="token keyword">let tomcat <span class="token operator">= <span class="token function">buildName<span class="token punctuation">(<span class="token string">'Tom'<span class="token punctuation">, <span class="token string">'Cat'<span class="token punctuation">)<span class="token punctuation">;
<span class="token keyword">let tom <span class="token operator">= <span class="token function">buildName<span class="token punctuation">(<span class="token string">'Tom'<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>需要注意的是,可选参数必须接在必需参数后面。换句话说,可选参数后面不允许再出现必需参数了:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">buildName<span class="token punctuation">(firstName<span class="token operator">?<span class="token operator">: <span class="token builtin">string<span class="token punctuation">, lastName<span class="token operator">: <span class="token builtin">string<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">if <span class="token punctuation">(firstName<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">return firstName <span class="token operator">+ <span class="token string">' ' <span class="token operator">+ lastName<span class="token punctuation">;
    <span class="token punctuation">} <span class="token keyword">else <span class="token punctuation">{
      <span class="token keyword">return lastName<span class="token punctuation">;
    <span class="token punctuation">}
<span class="token punctuation">}
<span class="token keyword">let tomcat <span class="token operator">= <span class="token function">buildName<span class="token punctuation">(<span class="token string">'Tom'<span class="token punctuation">, <span class="token string">'Cat'<span class="token punctuation">)<span class="token punctuation">;
<span class="token keyword">let tom <span class="token operator">= <span class="token function">buildName<span class="token punctuation">(<span class="token keyword">undefined<span class="token punctuation">, <span class="token string">'Tom'<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// index.ts(1,40): error TS1016: A required parameter cannot follow an optional parameter.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 id="%E5%8F%82%E6%95%B0%E9%BB%98%E8%AE%A4%E5%80%BC">8.5、参数默认值<br></h2>
<p>在 ES6 中,我们允许给函数的参数添加默认值,TypeScript 会将添加了默认值的参数识别为可选参数:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">buildName<span class="token punctuation">(firstName<span class="token operator">: <span class="token builtin">string<span class="token punctuation">, lastName<span class="token operator">: <span class="token builtin">string <span class="token operator">= <span class="token string">'Cat'<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">return firstName <span class="token operator">+ <span class="token string">' ' <span class="token operator">+ lastName<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">let tomcat <span class="token operator">= <span class="token function">buildName<span class="token punctuation">(<span class="token string">'Tom'<span class="token punctuation">, <span class="token string">'Cat'<span class="token punctuation">)<span class="token punctuation">;
<span class="token keyword">let tom <span class="token operator">= <span class="token function">buildName<span class="token punctuation">(<span class="token string">'Tom'<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>此时就不受「可选参数必须接在必需参数后面」的限制了:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">buildName<span class="token punctuation">(firstName<span class="token operator">: <span class="token builtin">string <span class="token operator">= <span class="token string">'Tom'<span class="token punctuation">, lastName<span class="token operator">: <span class="token builtin">string<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">return firstName <span class="token operator">+ <span class="token string">' ' <span class="token operator">+ lastName<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">let tomcat <span class="token operator">= <span class="token function">buildName<span class="token punctuation">(<span class="token string">'Tom'<span class="token punctuation">, <span class="token string">'Cat'<span class="token punctuation">)<span class="token punctuation">;
<span class="token keyword">let cat <span class="token operator">= <span class="token function">buildName<span class="token punctuation">(<span class="token keyword">undefined<span class="token punctuation">, <span class="token string">'Cat'<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<blockquote>
<p>关于默认参数,可以参考&nbsp;ES6 中函数参数的默认值。</p>
</blockquote>
<h2 id="%E5%89%A9%E4%BD%99%E5%8F%82%E6%95%B0">8.6、剩余参数<br></h2>
<p>ES6 中,可以使用&nbsp;<code>...rest</code>&nbsp;的方式获取函数中的剩余参数(rest 参数):</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function <span class="token function">push<span class="token punctuation">(<span class="token parameter">array<span class="token punctuation">, <span class="token spread operator">...items<span class="token punctuation">) <span class="token punctuation">{
    items<span class="token punctuation">.<span class="token method function property-access">forEach<span class="token punctuation">(<span class="token keyword">function<span class="token punctuation">(<span class="token parameter">item<span class="token punctuation">) <span class="token punctuation">{
      array<span class="token punctuation">.<span class="token method function property-access">push<span class="token punctuation">(item<span class="token punctuation">)<span class="token punctuation">;
    <span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let a<span class="token operator">: any<span class="token punctuation">[<span class="token punctuation">] <span class="token operator">= <span class="token punctuation">[<span class="token punctuation">]<span class="token punctuation">;
<span class="token function">push<span class="token punctuation">(a<span class="token punctuation">, <span class="token number">1<span class="token punctuation">, <span class="token number">2<span class="token punctuation">, <span class="token number">3<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>事实上,<code>items</code>&nbsp;是一个数组。所以我们可以用数组的类型来定义它:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">push<span class="token punctuation">(array<span class="token operator">: <span class="token builtin">any<span class="token punctuation">[<span class="token punctuation">]<span class="token punctuation">, <span class="token operator">...items<span class="token operator">: <span class="token builtin">any<span class="token punctuation">[<span class="token punctuation">]<span class="token punctuation">) <span class="token punctuation">{
    items<span class="token punctuation">.<span class="token function">forEach<span class="token punctuation">(<span class="token keyword">function<span class="token punctuation">(item<span class="token punctuation">) <span class="token punctuation">{
      array<span class="token punctuation">.<span class="token function">push<span class="token punctuation">(item<span class="token punctuation">)<span class="token punctuation">;
    <span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let a <span class="token operator">= <span class="token punctuation">[<span class="token punctuation">]<span class="token punctuation">;
<span class="token function">push<span class="token punctuation">(a<span class="token punctuation">, <span class="token number">1<span class="token punctuation">, <span class="token number">2<span class="token punctuation">, <span class="token number">3<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>注意,rest 参数只能是最后一个参数,关于 rest 参数,可以参考&nbsp;ES6 中的 rest 参数。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">...表示剩余,必须是数组类型</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> add(n1:number, ...n2:number[]):number
{
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(n2.length&gt;0<span style="color: rgba(0, 0, 0, 1)">){
      </span><span style="color: rgba(0, 0, 255, 1)">for</span>(let i=0;i&lt;n2.length;i++<span style="color: rgba(0, 0, 0, 1)">){
            n1</span>+=<span style="color: rgba(0, 0, 0, 1)">n2;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> n1;
    }
    </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> ++<span style="color: rgba(0, 0, 0, 1)">n1;
    }
}

console.log(add(</span>1));<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">2</span>
console.log(add(1,3)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">4</span>
console.log(add(1,2,3)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">6</span>
console.log(add(1,2,3,4,5,6)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">21</span></pre>
</div>
<h2 id="%E9%87%8D%E8%BD%BD">8.7、重载<br></h2>
<p>重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。</p>
<p>比如,我们需要实现一个函数&nbsp;<code>reverse</code>,输入数字&nbsp;<code>123</code>&nbsp;的时候,输出反转的数字&nbsp;<code>321</code>,输入字符串&nbsp;<code>'hello'</code>&nbsp;的时候,输出反转的字符串&nbsp;<code>'olleh'</code>。</p>
<p>利用联合类型,我们可以这么实现:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">reverse<span class="token punctuation">(x<span class="token operator">: <span class="token builtin">number <span class="token operator">| <span class="token builtin">string<span class="token punctuation">)<span class="token operator">: <span class="token builtin">number <span class="token operator">| <span class="token builtin">string <span class="token operator">| <span class="token keyword">void <span class="token punctuation">{
    <span class="token keyword">if <span class="token punctuation">(<span class="token keyword">typeof x <span class="token operator">=== <span class="token string">'number'<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">return <span class="token function">Number<span class="token punctuation">(x<span class="token punctuation">.<span class="token function">toString<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">.<span class="token function">split<span class="token punctuation">(<span class="token string">''<span class="token punctuation">)<span class="token punctuation">.<span class="token function">reverse<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">.<span class="token function">join<span class="token punctuation">(<span class="token string">''<span class="token punctuation">)<span class="token punctuation">)<span class="token punctuation">;
    <span class="token punctuation">} <span class="token keyword">else <span class="token keyword">if <span class="token punctuation">(<span class="token keyword">typeof x <span class="token operator">=== <span class="token string">'string'<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">return x<span class="token punctuation">.<span class="token function">split<span class="token punctuation">(<span class="token string">''<span class="token punctuation">)<span class="token punctuation">.<span class="token function">reverse<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">.<span class="token function">join<span class="token punctuation">(<span class="token string">''<span class="token punctuation">)<span class="token punctuation">;
    <span class="token punctuation">}
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>然而这样有一个缺点,就是不能够精确的表达,输入为数字的时候,输出也应该为数字,输入为字符串的时候,输出也应该为字符串。</p>
<p>这时,我们可以使用重载定义多个&nbsp;<code>reverse</code>&nbsp;的函数类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">reverse<span class="token punctuation">(x<span class="token operator">: <span class="token builtin">number<span class="token punctuation">)<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token keyword">function <span class="token function">reverse<span class="token punctuation">(x<span class="token operator">: <span class="token builtin">string<span class="token punctuation">)<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
<span class="token keyword">function <span class="token function">reverse<span class="token punctuation">(x<span class="token operator">: <span class="token builtin">number <span class="token operator">| <span class="token builtin">string<span class="token punctuation">)<span class="token operator">: <span class="token builtin">number <span class="token operator">| <span class="token builtin">string <span class="token operator">| <span class="token keyword">void <span class="token punctuation">{
    <span class="token keyword">if <span class="token punctuation">(<span class="token keyword">typeof x <span class="token operator">=== <span class="token string">'number'<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">return <span class="token function">Number<span class="token punctuation">(x<span class="token punctuation">.<span class="token function">toString<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">.<span class="token function">split<span class="token punctuation">(<span class="token string">''<span class="token punctuation">)<span class="token punctuation">.<span class="token function">reverse<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">.<span class="token function">join<span class="token punctuation">(<span class="token string">''<span class="token punctuation">)<span class="token punctuation">)<span class="token punctuation">;
    <span class="token punctuation">} <span class="token keyword">else <span class="token keyword">if <span class="token punctuation">(<span class="token keyword">typeof x <span class="token operator">=== <span class="token string">'string'<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">return x<span class="token punctuation">.<span class="token function">split<span class="token punctuation">(<span class="token string">''<span class="token punctuation">)<span class="token punctuation">.<span class="token function">reverse<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">.<span class="token function">join<span class="token punctuation">(<span class="token string">''<span class="token punctuation">)<span class="token punctuation">;
    <span class="token punctuation">}
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上例中,我们重复定义了多次函数&nbsp;<code>reverse</code>,前几次都是函数定义,最后一次是函数实现。在编辑器的代码提示中,可以正确的看到前两个提示。</p>
<p>注意,TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。</p>
<h1>&nbsp;九、类型断言</h1>
<p>类型断言(Type Assertion)可以用来手动指定一个值的类型。</p>
<h2 id="%E8%AF%AD%E6%B3%95">9.1、语法<br></h2>
<pre class="language-ts"><code class="language-ts">值 <span class="token keyword">as 类型
</span></code></pre>
<p>或</p>
<pre class="language-ts"><code class="language-ts"><span class="token operator">&lt;类型<span class="token operator">&gt;值
</span></span></code></pre>
<p>在 tsx 语法(React 的 jsx 语法的 ts 版)中必须使用前者,即&nbsp;<code>值 as 类型</code>。</p>
<p>形如&nbsp;<code>&lt;Foo&gt;</code>&nbsp;的语法在 tsx 中表示的是一个&nbsp;<code>ReactNode</code>,在 ts 中除了表示类型断言之外,也可能是表示一个泛型。</p>
<p>故建议大家在使用类型断言时,统一使用&nbsp;<code>值 as 类型</code>&nbsp;这样的语法。</p>
<h2 id="%E7%B1%BB%E5%9E%8B%E6%96%AD%E8%A8%80%E7%9A%84%E7%94%A8%E9%80%94">9.2、类型断言的用途<br></h2>
<p>类型断言的常见用途有以下几种:</p>
<h3 id="%E5%B0%86%E4%B8%80%E4%B8%AA%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B%E6%96%AD%E8%A8%80%E4%B8%BA%E5%85%B6%E4%B8%AD%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%9E%8B">9.2.1、将一个联合类型断言为其中一个类型<br></h3>
<p>之前提到过,当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型中共有的属性或方法:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">interface <span class="token class-name">Fish <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">swim<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">function <span class="token function">getName<span class="token punctuation">(animal<span class="token operator">: Cat <span class="token operator">| Fish<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">return animal<span class="token punctuation">.name<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>而有时候,我们确实需要在还不确定类型的时候就访问其中一个类型特有的属性或方法,比如:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">interface <span class="token class-name">Fish <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">swim<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">function <span class="token function">isFish<span class="token punctuation">(animal<span class="token operator">: Cat <span class="token operator">| Fish<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">if <span class="token punctuation">(<span class="token keyword">typeof animal<span class="token punctuation">.swim <span class="token operator">=== <span class="token string">'function'<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">return <span class="token boolean">true<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return <span class="token boolean">false<span class="token punctuation">;
<span class="token punctuation">}

<span class="token comment">// index.ts:11:23 - error TS2339: Property 'swim' does not exist on type 'Cat | Fish'.
<span class="token comment">//   Property 'swim' does not exist on type 'Cat'.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上面的例子中,获取&nbsp;<code>animal.swim</code>&nbsp;的时候会报错。</p>
<p>此时可以使用类型断言,将&nbsp;<code>animal</code>&nbsp;断言成&nbsp;<code>Fish</code>:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">interface <span class="token class-name">Fish <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">swim<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">function <span class="token function">isFish<span class="token punctuation">(animal<span class="token operator">: Cat <span class="token operator">| Fish<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">if <span class="token punctuation">(<span class="token keyword">typeof <span class="token punctuation">(animal <span class="token keyword">as Fish<span class="token punctuation">)<span class="token punctuation">.swim <span class="token operator">=== <span class="token string">'function'<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">return <span class="token boolean">true<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return <span class="token boolean">false<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>这样就可以解决访问&nbsp;<code>animal.swim</code>&nbsp;时报错的问题了。</p>
<p>需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">interface <span class="token class-name">Fish <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">swim<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">function <span class="token function">swim<span class="token punctuation">(animal<span class="token operator">: Cat <span class="token operator">| Fish<span class="token punctuation">) <span class="token punctuation">{
    <span class="token punctuation">(animal <span class="token keyword">as Fish<span class="token punctuation">)<span class="token punctuation">.<span class="token function">swim<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">const tom<span class="token operator">: Cat <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'Tom'<span class="token punctuation">,
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{ <span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(<span class="token string">'run'<span class="token punctuation">) <span class="token punctuation">}
<span class="token punctuation">}<span class="token punctuation">;
<span class="token function">swim<span class="token punctuation">(tom<span class="token punctuation">)<span class="token punctuation">;
<span class="token comment">// Uncaught TypeError: animal.swim is not a function`
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上面的例子编译时不会报错,但在运行时会报错:</p>
<pre class="language-autoit"><code class="language-autoit">Uncaught TypeError<span class="token punctuation">: animal<span class="token punctuation">.swim is <span class="token operator">not a function`
</span></span></span></code></pre>
<p>原因是&nbsp;<code>(animal as Fish).swim()</code>&nbsp;这段代码隐藏了&nbsp;<code>animal</code>&nbsp;可能为&nbsp;<code>Cat</code>&nbsp;的情况,将&nbsp;<code>animal</code>&nbsp;直接断言为&nbsp;<code>Fish</code>&nbsp;了,而 TypeScript 编译器信任了我们的断言,故在调用&nbsp;<code>swim()</code>&nbsp;时没有编译错误。</p>
<p>可是&nbsp;<code>swim</code>&nbsp;函数接受的参数是&nbsp;<code>Cat | Fish</code>,一旦传入的参数是&nbsp;<code>Cat</code>&nbsp;类型的变量,由于&nbsp;<code>Cat</code>&nbsp;上没有&nbsp;<code>swim</code>&nbsp;方法,就会导致运行时错误了。</p>
<p>总之,使用类型断言时一定要格外小心,尽量避免断言后调用方法或引用深层属性,以减少不必要的运行时错误。</p>
<h3 id="%E5%B0%86%E4%B8%80%E4%B8%AA%E7%88%B6%E7%B1%BB%E6%96%AD%E8%A8%80%E4%B8%BA%E6%9B%B4%E5%8A%A0%E5%85%B7%E4%BD%93%E7%9A%84%E5%AD%90%E7%B1%BB">9.2.2、将一个父类断言为更加具体的子类<br></h3>
<p>当类之间有继承关系时,类型断言也是很常见的:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <span class="token class-name">ApiError <span class="token keyword">extends <span class="token class-name">Error <span class="token punctuation">{
    code<span class="token operator">: <span class="token builtin">number <span class="token operator">= <span class="token number">0<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">class <span class="token class-name">HttpError <span class="token keyword">extends <span class="token class-name">Error <span class="token punctuation">{
    statusCode<span class="token operator">: <span class="token builtin">number <span class="token operator">= <span class="token number">200<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">function <span class="token function">isApiError<span class="token punctuation">(error<span class="token operator">: Error<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">if <span class="token punctuation">(<span class="token keyword">typeof <span class="token punctuation">(error <span class="token keyword">as ApiError<span class="token punctuation">)<span class="token punctuation">.code <span class="token operator">=== <span class="token string">'number'<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">return <span class="token boolean">true<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return <span class="token boolean">false<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上面的例子中,我们声明了函数&nbsp;<code>isApiError</code>,它用来判断传入的参数是不是&nbsp;<code>ApiError</code>&nbsp;类型,为了实现这样一个函数,它的参数的类型肯定得是比较抽象的父类&nbsp;<code>Error</code>,这样的话这个函数就能接受&nbsp;<code>Error</code>&nbsp;或它的子类作为参数了。</p>
<p>但是由于父类&nbsp;<code>Error</code>&nbsp;中没有&nbsp;<code>code</code>&nbsp;属性,故直接获取&nbsp;<code>error.code</code>&nbsp;会报错,需要使用类型断言获取&nbsp;<code>(error as ApiError).code</code>。</p>
<p>大家可能会注意到,在这个例子中有一个更合适的方式来判断是不是&nbsp;<code>ApiError</code>,那就是使用&nbsp;<code>instanceof</code>:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <span class="token class-name">ApiError <span class="token keyword">extends <span class="token class-name">Error <span class="token punctuation">{
    code<span class="token operator">: <span class="token builtin">number <span class="token operator">= <span class="token number">0<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">class <span class="token class-name">HttpError <span class="token keyword">extends <span class="token class-name">Error <span class="token punctuation">{
    statusCode<span class="token operator">: <span class="token builtin">number <span class="token operator">= <span class="token number">200<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">function <span class="token function">isApiError<span class="token punctuation">(error<span class="token operator">: Error<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">if <span class="token punctuation">(error <span class="token keyword">instanceof <span class="token class-name">ApiError<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">return <span class="token boolean">true<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return <span class="token boolean">false<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上面的例子中,确实使用&nbsp;<code>instanceof</code>&nbsp;更加合适,因为&nbsp;<code>ApiError</code>&nbsp;是一个 JavaScript 的类,能够通过&nbsp;<code>instanceof</code>&nbsp;来判断&nbsp;<code>error</code>&nbsp;是否是它的实例。</p>
<p>但是有的情况下&nbsp;<code>ApiError</code>&nbsp;和&nbsp;<code>HttpError</code>&nbsp;不是一个真正的类,而只是一个 TypeScript 的接口(<code>interface</code>),接口是一个类型,不是一个真正的值,它在编译结果中会被删除,当然就无法使用&nbsp;<code>instanceof</code>&nbsp;来做运行时判断了:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">ApiError <span class="token keyword">extends <span class="token class-name">Error <span class="token punctuation">{
    code<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">interface <span class="token class-name">HttpError <span class="token keyword">extends <span class="token class-name">Error <span class="token punctuation">{
    statusCode<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">function <span class="token function">isApiError<span class="token punctuation">(error<span class="token operator">: Error<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">if <span class="token punctuation">(error <span class="token keyword">instanceof <span class="token class-name">ApiError<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">return <span class="token boolean">true<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return <span class="token boolean">false<span class="token punctuation">;
<span class="token punctuation">}

<span class="token comment">// index.ts:9:26 - error TS2693: 'ApiError' only refers to a type, but is being used as a value here.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>此时就只能用类型断言,通过判断是否存在&nbsp;<code>code</code>&nbsp;属性,来判断传入的参数是不是&nbsp;<code>ApiError</code>&nbsp;了:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">ApiError <span class="token keyword">extends <span class="token class-name">Error <span class="token punctuation">{
    code<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">interface <span class="token class-name">HttpError <span class="token keyword">extends <span class="token class-name">Error <span class="token punctuation">{
    statusCode<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">function <span class="token function">isApiError<span class="token punctuation">(error<span class="token operator">: Error<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">if <span class="token punctuation">(<span class="token keyword">typeof <span class="token punctuation">(error <span class="token keyword">as ApiError<span class="token punctuation">)<span class="token punctuation">.code <span class="token operator">=== <span class="token string">'number'<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">return <span class="token boolean">true<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return <span class="token boolean">false<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h3 id="%E5%B0%86%E4%BB%BB%E4%BD%95%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%9E%8B%E6%96%AD%E8%A8%80%E4%B8%BA-any">9.2.3、将任何一个类型断言为&nbsp;<code>any</code><br></h3>
<p>理想情况下,TypeScript 的类型系统运转良好,每个值的类型都具体而精确。</p>
<p>当我们引用一个在此类型上不存在的属性或方法时,就会报错:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">const foo<span class="token operator">: <span class="token builtin">number <span class="token operator">= <span class="token number">1<span class="token punctuation">;
foo<span class="token punctuation">.length <span class="token operator">= <span class="token number">1<span class="token punctuation">;

<span class="token comment">// index.ts:2:5 - error TS2339: Property 'length' does not exist on type 'number'.
</span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上面的例子中,数字类型的变量&nbsp;<code>foo</code>&nbsp;上是没有&nbsp;<code>length</code>&nbsp;属性的,故 TypeScript 给出了相应的错误提示。</p>
<p>这种错误提示显然是非常有用的。</p>
<p>但有的时候,我们非常确定这段代码不会出错,比如下面这个例子:</p>
<pre class="language-ts"><code class="language-ts">window<span class="token punctuation">.foo <span class="token operator">= <span class="token number">1<span class="token punctuation">;

<span class="token comment">// index.ts:1:8 - error TS2339: Property 'foo' does not exist on type 'Window &amp; typeof globalThis'.
</span></span></span></span></span></code></pre>
<p>上面的例子中,我们需要将&nbsp;<code>window</code>&nbsp;上添加一个属性&nbsp;<code>foo</code>,但 TypeScript 编译时会报错,提示我们&nbsp;<code>window</code>&nbsp;上不存在&nbsp;<code>foo</code>&nbsp;属性。</p>
<p>此时我们可以使用&nbsp;<code>as any</code>&nbsp;临时将&nbsp;<code>window</code>&nbsp;断言为&nbsp;<code>any</code>&nbsp;类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token punctuation">(window <span class="token keyword">as <span class="token builtin">any<span class="token punctuation">)<span class="token punctuation">.foo <span class="token operator">= <span class="token number">1<span class="token punctuation">;
</span></span></span></span></span></span></span></span></code></pre>
<p>在&nbsp;<code>any</code>&nbsp;类型的变量上,访问任何属性都是允许的。</p>
<p>需要注意的是,将一个变量断言为&nbsp;<code>any</code>&nbsp;可以说是解决 TypeScript 中类型问题的最后一个手段。</p>
<p>它极有可能掩盖了真正的类型错误,所以如果不是非常确定,就不要使用&nbsp;<code>as any</code>。</p>
<p>上面的例子中,我们也可以通过[扩展 window 的类型(TODO)][]解决这个错误,不过如果只是临时的增加&nbsp;<code>foo</code>&nbsp;属性,<code>as any</code>&nbsp;会更加方便。</p>
<p>总之,一方面不能滥用&nbsp;<code>as any</code>,另一方面也不要完全否定它的作用,我们需要在类型的严格性和开发的便利性之间掌握平衡(这也是&nbsp;TypeScript 的设计理念之一),才能发挥出 TypeScript 最大的价值。</p>
<h3 id="%E5%B0%86-any-%E6%96%AD%E8%A8%80%E4%B8%BA%E4%B8%80%E4%B8%AA%E5%85%B7%E4%BD%93%E7%9A%84%E7%B1%BB%E5%9E%8B">9.2.4、将&nbsp;<code>any</code>&nbsp;断言为一个具体的类型<br></h3>
<p>在日常的开发中,我们不可避免的需要处理&nbsp;<code>any</code>&nbsp;类型的变量,它们可能是由于第三方库未能定义好自己的类型,也有可能是历史遗留的或其他人编写的烂代码,还可能是受到 TypeScript 类型系统的限制而无法精确定义类型的场景。</p>
<p>遇到&nbsp;<code>any</code>&nbsp;类型的变量时,我们可以选择无视它,任由它滋生更多的&nbsp;<code>any</code>。</p>
<p>我们也可以选择改进它,通过类型断言及时的把&nbsp;<code>any</code>&nbsp;断言为精确的类型,亡羊补牢,使我们的代码向着高可维护性的目标发展。</p>
<p>举例来说,历史遗留的代码中有个&nbsp;<code>getCacheData</code>,它的返回值是&nbsp;<code>any</code>:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">getCacheData<span class="token punctuation">(key<span class="token operator">: <span class="token builtin">string<span class="token punctuation">)<span class="token operator">: <span class="token builtin">any <span class="token punctuation">{
    <span class="token keyword">return <span class="token punctuation">(window <span class="token keyword">as <span class="token builtin">any<span class="token punctuation">)<span class="token punctuation">.cache<span class="token punctuation"><span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>那么我们在使用它时,最好能够将调用了它之后的返回值断言成一个精确的类型,这样就方便了后续的操作:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">getCacheData<span class="token punctuation">(key<span class="token operator">: <span class="token builtin">string<span class="token punctuation">)<span class="token operator">: <span class="token builtin">any <span class="token punctuation">{
    <span class="token keyword">return <span class="token punctuation">(window <span class="token keyword">as <span class="token builtin">any<span class="token punctuation">)<span class="token punctuation">.cache<span class="token punctuation"><span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">const tom <span class="token operator">= <span class="token function">getCacheData<span class="token punctuation">(<span class="token string">'tom'<span class="token punctuation">) <span class="token keyword">as Cat<span class="token punctuation">;
tom<span class="token punctuation">.<span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上面的例子中,我们调用完&nbsp;<code>getCacheData</code>&nbsp;之后,立即将它断言为&nbsp;<code>Cat</code>&nbsp;类型。这样的话明确了&nbsp;<code>tom</code>&nbsp;的类型,后续对&nbsp;<code>tom</code>&nbsp;的访问时就有了代码补全,提高了代码的可维护性。</p>
<h2 id="%E7%B1%BB%E5%9E%8B%E6%96%AD%E8%A8%80%E7%9A%84%E9%99%90%E5%88%B6">9.3、类型断言的限制<br></h2>
<blockquote>
<p>本小节的前置知识点:[结构类型系统(TODO)][]、[类型兼容性(TODO)][]</p>





















</blockquote>
<p>从上面的例子中,我们可以总结出:</p>
<ul>
<li>联合类型可以被断言为其中一个类型</li>
<li>父类可以被断言为子类</li>
<li>任何类型都可以被断言为 any</li>
<li>any 可以被断言为任何类型</li>





















</ul>
<p>那么类型断言有没有什么限制呢?是不是任何一个类型都可以被断言为任何另一个类型呢?</p>
<p>答案是否定的——并不是任何一个类型都可以被断言为任何另一个类型。</p>
<p>具体来说,若&nbsp;<code>A</code>&nbsp;兼容&nbsp;<code>B</code>,那么&nbsp;<code>A</code>&nbsp;能够被断言为&nbsp;<code>B</code>,<code>B</code>&nbsp;也能被断言为&nbsp;<code>A</code>。</p>
<p>下面我们通过一个简化的例子,来理解类型断言的限制:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Animal <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let tom<span class="token operator">: Cat <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'Tom'<span class="token punctuation">,
    <span class="token function-variable function">run<span class="token operator">: <span class="token punctuation">(<span class="token punctuation">) <span class="token operator">=&gt; <span class="token punctuation">{ <span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(<span class="token string">'run'<span class="token punctuation">) <span class="token punctuation">}
<span class="token punctuation">}<span class="token punctuation">;
<span class="token keyword">let animal<span class="token operator">: Animal <span class="token operator">= tom<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>我们知道,TypeScript 是结构类型系统,类型之间的对比只会比较它们最终的结构,而会忽略它们定义时的关系。</p>
<p>在上面的例子中,<code>Cat</code>&nbsp;包含了&nbsp;<code>Animal</code>&nbsp;中的所有属性,除此之外,它还有一个额外的方法&nbsp;<code>run</code>。TypeScript 并不关心&nbsp;<code>Cat</code>&nbsp;和&nbsp;<code>Animal</code>&nbsp;之间定义时是什么关系,而只会看它们最终的结构有什么关系——所以它与&nbsp;<code>Cat extends Animal</code>&nbsp;是等价的:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Animal <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">interface <span class="token class-name">Cat <span class="token keyword">extends <span class="token class-name">Animal <span class="token punctuation">{
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>那么也不难理解为什么&nbsp;<code>Cat</code>&nbsp;类型的&nbsp;<code>tom</code>&nbsp;可以赋值给&nbsp;<code>Animal</code>&nbsp;类型的&nbsp;<code>animal</code>&nbsp;了——就像面向对象编程中我们可以将子类的实例赋值给类型为父类的变量。</p>
<p>我们把它换成 TypeScript 中更专业的说法,即:<code>Animal</code>&nbsp;兼容&nbsp;<code>Cat</code>。</p>
<p>当&nbsp;<code>Animal</code>&nbsp;兼容&nbsp;<code>Cat</code>&nbsp;时,它们就可以互相进行类型断言了:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Animal <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">function <span class="token function">testAnimal<span class="token punctuation">(animal<span class="token operator">: Animal<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">return <span class="token punctuation">(animal <span class="token keyword">as Cat<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">function <span class="token function">testCat<span class="token punctuation">(cat<span class="token operator">: Cat<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">return <span class="token punctuation">(cat <span class="token keyword">as Animal<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>这样的设计其实也很容易就能理解:</p>
<ul>
<li>允许&nbsp;<code>animal as Cat</code>&nbsp;是因为「父类可以被断言为子类」,这个前面已经学习过了</li>
<li>允许&nbsp;<code>cat as Animal</code>&nbsp;是因为既然子类拥有父类的属性和方法,那么被断言为父类,获取父类的属性、调用父类的方法,就不会有任何问题,故「子类可以被断言为父类」</li>
</ul>
<p>需要注意的是,这里我们使用了简化的父类子类的关系来表达类型的兼容性,而实际上 TypeScript 在判断类型的兼容性时,比这种情况复杂很多,详细请参考[类型的兼容性(TODO)][]章节。</p>
<p>总之,若&nbsp;<code>A</code>&nbsp;兼容&nbsp;<code>B</code>,那么&nbsp;<code>A</code>&nbsp;能够被断言为&nbsp;<code>B</code>,<code>B</code>&nbsp;也能被断言为&nbsp;<code>A</code>。</p>
<p>同理,若&nbsp;<code>B</code>&nbsp;兼容&nbsp;<code>A</code>,那么&nbsp;<code>A</code>&nbsp;能够被断言为&nbsp;<code>B</code>,<code>B</code>&nbsp;也能被断言为&nbsp;<code>A</code>。</p>
<p>所以这也可以换一种说法:</p>
<p>要使得&nbsp;<code>A</code>&nbsp;能够被断言为&nbsp;<code>B</code>,只需要&nbsp;<code>A</code>&nbsp;兼容&nbsp;<code>B</code>&nbsp;或&nbsp;<code>B</code>&nbsp;兼容&nbsp;<code>A</code>&nbsp;即可,这也是为了在类型断言时的安全考虑,毕竟毫无根据的断言是非常危险的。</p>
<p>综上所述:</p>
<ul>
<li>联合类型可以被断言为其中一个类型</li>
<li>父类可以被断言为子类</li>
<li>任何类型都可以被断言为 any</li>
<li>any 可以被断言为任何类型</li>
<li>要使得&nbsp;<code>A</code>&nbsp;能够被断言为&nbsp;<code>B</code>,只需要&nbsp;<code>A</code>&nbsp;兼容&nbsp;<code>B</code>&nbsp;或&nbsp;<code>B</code>&nbsp;兼容&nbsp;<code>A</code>&nbsp;即可</li>
</ul>
<p>其实前四种情况都是最后一个的特例。</p>
<h2 id="%E5%8F%8C%E9%87%8D%E6%96%AD%E8%A8%80">9.4、双重断言<br></h2>
<p>既然:</p>
<ul>
<li>任何类型都可以被断言为 any</li>
<li>any 可以被断言为任何类型</li>





















</ul>
<p>那么我们是不是可以使用双重断言&nbsp;<code>as any as Foo</code>&nbsp;来将任何一个类型断言为任何另一个类型呢?</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">interface <span class="token class-name">Fish <span class="token punctuation">{
    <span class="token function">swim<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">function <span class="token function">testCat<span class="token punctuation">(cat<span class="token operator">: Cat<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">return <span class="token punctuation">(cat <span class="token keyword">as <span class="token builtin">any <span class="token keyword">as Fish<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>在上面的例子中,若直接使用&nbsp;<code>cat as Fish</code>&nbsp;肯定会报错,因为&nbsp;<code>Cat</code>&nbsp;和&nbsp;<code>Fish</code>&nbsp;互相都不兼容。</p>
<p>但是若使用双重断言,则可以打破「要使得&nbsp;<code>A</code>&nbsp;能够被断言为&nbsp;<code>B</code>,只需要&nbsp;<code>A</code>&nbsp;兼容&nbsp;<code>B</code>&nbsp;或&nbsp;<code>B</code>&nbsp;兼容&nbsp;<code>A</code>&nbsp;即可」的限制,将任何一个类型断言为任何另一个类型。</p>
<p>若你使用了这种双重断言,那么十有八九是非常错误的,它很可能会导致运行时错误。</p>
<p>除非迫不得已,千万别用双重断言。</p>
<h2 id="%E7%B1%BB%E5%9E%8B%E6%96%AD%E8%A8%80-vs-%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2">9.5、类型断言 vs 类型转换<br></h2>
<p>类型断言只会影响 TypeScript 编译时的类型,类型断言语句在编译结果中会被删除:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">toBoolean<span class="token punctuation">(something<span class="token operator">: <span class="token builtin">any<span class="token punctuation">)<span class="token operator">: <span class="token builtin">boolean <span class="token punctuation">{
    <span class="token keyword">return something <span class="token keyword">as <span class="token builtin">boolean<span class="token punctuation">;
<span class="token punctuation">}

<span class="token function">toBoolean<span class="token punctuation">(<span class="token number">1<span class="token punctuation">)<span class="token punctuation">;
<span class="token comment">// 返回值为 1
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>在上面的例子中,将&nbsp;<code>something</code>&nbsp;断言为&nbsp;<code>boolean</code>&nbsp;虽然可以通过编译,但是并没有什么用,代码在编译后会变成:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function <span class="token function">toBoolean<span class="token punctuation">(<span class="token parameter">something<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword control-flow">return something<span class="token punctuation">;
<span class="token punctuation">}

<span class="token function">toBoolean<span class="token punctuation">(<span class="token number">1<span class="token punctuation">)<span class="token punctuation">;
<span class="token comment">// 返回值为 1
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>所以类型断言不是类型转换,它不会真的影响到变量的类型。</p>
<p>若要进行类型转换,需要直接调用类型转换的方法:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">toBoolean<span class="token punctuation">(something<span class="token operator">: <span class="token builtin">any<span class="token punctuation">)<span class="token operator">: <span class="token builtin">boolean <span class="token punctuation">{
    <span class="token keyword">return <span class="token function">Boolean<span class="token punctuation">(something<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}

<span class="token function">toBoolean<span class="token punctuation">(<span class="token number">1<span class="token punctuation">)<span class="token punctuation">;
<span class="token comment">// 返回值为 true
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 id="%E7%B1%BB%E5%9E%8B%E6%96%AD%E8%A8%80-vs-%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E">9.6、类型断言 vs 类型声明<br></h2>
<p>在这个例子中:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">getCacheData<span class="token punctuation">(key<span class="token operator">: <span class="token builtin">string<span class="token punctuation">)<span class="token operator">: <span class="token builtin">any <span class="token punctuation">{
    <span class="token keyword">return <span class="token punctuation">(window <span class="token keyword">as <span class="token builtin">any<span class="token punctuation">)<span class="token punctuation">.cache<span class="token punctuation"><span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">const tom <span class="token operator">= <span class="token function">getCacheData<span class="token punctuation">(<span class="token string">'tom'<span class="token punctuation">) <span class="token keyword">as Cat<span class="token punctuation">;
tom<span class="token punctuation">.<span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>我们使用&nbsp;<code>as Cat</code>&nbsp;将&nbsp;<code>any</code>&nbsp;类型断言为了&nbsp;<code>Cat</code>&nbsp;类型。</p>
<p>但实际上还有其他方式可以解决这个问题:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">getCacheData<span class="token punctuation">(key<span class="token operator">: <span class="token builtin">string<span class="token punctuation">)<span class="token operator">: <span class="token builtin">any <span class="token punctuation">{
    <span class="token keyword">return <span class="token punctuation">(window <span class="token keyword">as <span class="token builtin">any<span class="token punctuation">)<span class="token punctuation">.cache<span class="token punctuation"><span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">const tom<span class="token operator">: Cat <span class="token operator">= <span class="token function">getCacheData<span class="token punctuation">(<span class="token string">'tom'<span class="token punctuation">)<span class="token punctuation">;
tom<span class="token punctuation">.<span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上面的例子中,我们通过类型声明的方式,将&nbsp;<code>tom</code>&nbsp;声明为&nbsp;<code>Cat</code>,然后再将&nbsp;<code>any</code>&nbsp;类型的&nbsp;<code>getCacheData('tom')</code>&nbsp;赋值给&nbsp;<code>Cat</code>&nbsp;类型的&nbsp;<code>tom</code>。</p>
<p>这和类型断言是非常相似的,而且产生的结果也几乎是一样的——<code>tom</code>&nbsp;在接下来的代码中都变成了&nbsp;<code>Cat</code>&nbsp;类型。</p>
<p>它们的区别,可以通过这个例子来理解:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Animal <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">const animal<span class="token operator">: Animal <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'tom'
<span class="token punctuation">}<span class="token punctuation">;
<span class="token keyword">let tom <span class="token operator">= animal <span class="token keyword">as Cat<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>在上面的例子中,由于&nbsp;<code>Animal</code>&nbsp;兼容&nbsp;<code>Cat</code>,故可以将&nbsp;<code>animal</code>&nbsp;断言为&nbsp;<code>Cat</code>&nbsp;赋值给&nbsp;<code>tom</code>。</p>
<p>但是若直接声明&nbsp;<code>tom</code>&nbsp;为&nbsp;<code>Cat</code>&nbsp;类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Animal <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">const animal<span class="token operator">: Animal <span class="token operator">= <span class="token punctuation">{
    name<span class="token operator">: <span class="token string">'tom'
<span class="token punctuation">}<span class="token punctuation">;
<span class="token keyword">let tom<span class="token operator">: Cat <span class="token operator">= animal<span class="token punctuation">;

<span class="token comment">// index.ts:12:5 - error TS2741: Property 'run' is missing in type 'Animal' but required in type 'Cat'.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>则会报错,不允许将&nbsp;<code>animal</code>&nbsp;赋值为&nbsp;<code>Cat</code>&nbsp;类型的&nbsp;<code>tom</code>。</p>
<p>这很容易理解,<code>Animal</code>&nbsp;可以看作是&nbsp;<code>Cat</code>&nbsp;的父类,当然不能将父类的实例赋值给类型为子类的变量。</p>
<p>深入的讲,它们的核心区别就在于:</p>
<ul>
<li><code>animal</code>&nbsp;断言为&nbsp;<code>Cat</code>,只需要满足&nbsp;<code>Animal</code>&nbsp;兼容&nbsp;<code>Cat</code>&nbsp;或&nbsp;<code>Cat</code>&nbsp;兼容&nbsp;<code>Animal</code>&nbsp;即可</li>
<li><code>animal</code>&nbsp;赋值给&nbsp;<code>tom</code>,需要满足&nbsp;<code>Cat</code>&nbsp;兼容&nbsp;<code>Animal</code>&nbsp;才行</li>
</ul>
<p>但是&nbsp;<code>Cat</code>&nbsp;并不兼容&nbsp;<code>Animal</code>。</p>
<p>而在前一个例子中,由于&nbsp;<code>getCacheData('tom')</code>&nbsp;是&nbsp;<code>any</code>&nbsp;类型,<code>any</code>&nbsp;兼容&nbsp;<code>Cat</code>,<code>Cat</code>&nbsp;也兼容&nbsp;<code>any</code>,故</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">const tom <span class="token operator">= <span class="token function">getCacheData<span class="token punctuation">(<span class="token string">'tom'<span class="token punctuation">) <span class="token keyword">as Cat<span class="token punctuation">;
</span></span></span></span></span></span></span></span></code></pre>
<p>等价于</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">const tom<span class="token operator">: Cat <span class="token operator">= <span class="token function">getCacheData<span class="token punctuation">(<span class="token string">'tom'<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></code></pre>
<p>知道了它们的核心区别,就知道了类型声明是比类型断言更加严格的。</p>
<p>所以为了增加代码的质量,我们最好优先使用类型声明,这也比类型断言的&nbsp;<code>as</code>&nbsp;语法更加优雅。</p>
<h2 id="%E7%B1%BB%E5%9E%8B%E6%96%AD%E8%A8%80-vs-%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E">9.7、类型断言 vs 泛型</h2>
<blockquote>
<p>本小节的前置知识点:泛型</p>
</blockquote>
<p>还是这个例子:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">getCacheData<span class="token punctuation">(key<span class="token operator">: <span class="token builtin">string<span class="token punctuation">)<span class="token operator">: <span class="token builtin">any <span class="token punctuation">{
    <span class="token keyword">return <span class="token punctuation">(window <span class="token keyword">as <span class="token builtin">any<span class="token punctuation">)<span class="token punctuation">.cache<span class="token punctuation"><span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">const tom <span class="token operator">= <span class="token function">getCacheData<span class="token punctuation">(<span class="token string">'tom'<span class="token punctuation">) <span class="token keyword">as Cat<span class="token punctuation">;
tom<span class="token punctuation">.<span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>我们还有第三种方式可以解决这个问题,那就是泛型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token generic-function"><span class="token function">getCacheData<span class="token generic class-name"><span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt;<span class="token punctuation">(key<span class="token operator">: <span class="token builtin">string<span class="token punctuation">)<span class="token operator">: <span class="token constant">T <span class="token punctuation">{
    <span class="token keyword">return <span class="token punctuation">(window <span class="token keyword">as <span class="token builtin">any<span class="token punctuation">)<span class="token punctuation">.cache<span class="token punctuation"><span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">interface <span class="token class-name">Cat <span class="token punctuation">{
    name<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;
    <span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token keyword">void<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">const tom <span class="token operator">= <span class="token generic-function"><span class="token function">getCacheData<span class="token generic class-name"><span class="token operator">&lt;Cat<span class="token operator">&gt;<span class="token punctuation">(<span class="token string">'tom'<span class="token punctuation">)<span class="token punctuation">;
tom<span class="token punctuation">.<span class="token function">run<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>通过给&nbsp;<code>getCacheData</code>&nbsp;函数添加了一个泛型&nbsp;<code>&lt;T&gt;</code>,我们可以更加规范的实现对&nbsp;<code>getCacheData</code>&nbsp;返回值的约束,这也同时去除掉了代码中的&nbsp;<code>any</code>,是最优的一个解决方案。</p>
<h1>十、问号与叹号</h1>
<p><img src="https://img2022.cnblogs.com/blog/63651/202209/63651-20220922160100591-594985626.png" alt=""></p>
<h1>&nbsp;十一、视频</h1>
<p>&nbsp;【TypeScript】&nbsp;https://www.bilibili.com/video/BV1rT411T7JN?share_source=copy_web&amp;vd_source=475a31f3c5d6353a782007cd4c638a8a</p><br><br>
来源:https://www.cnblogs.com/best/p/16468787.html
頁: [1]
查看完整版本: TypeScript学习笔记(二)—— TypeScript基础