晓莲当 發表於 2022-9-29 15:53:00

TypeScript学习笔记(四)—— TypeScript提高

<h1>一、类型type</h1>
<h2>1.1、定义</h2>
<p>Type又叫类型别名(type alias),作用是给一个类型起一个新名字,不仅支持interface定义的对象结构,还支持基本类型、联合类型、交叉类型、元组等任何你需要手写的类型。</p>
<div class="cnblogs_code">
<pre>type Num = number; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 基本类型</span>
type StringOrNum = string | number; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 联合类型</span>
type Person = {name: string}; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 对象类型</span>
type User = person &amp; { age: number } <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 交叉类型</span>
type Data = ; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 元组</span>
type Fun = () =&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)"> 函数类型</span></pre>
</div>
<p>类型别名用来给一个类型起个新名字。</p>
<p id="%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%8B%E5%AD%90"><strong>简单的例子</strong><br></p>
<div class="cnblogs_code">
<pre>type Name =<span style="color: rgba(0, 0, 0, 1)"> string;
type NameResolver </span>= () =&gt;<span style="color: rgba(0, 0, 0, 1)"> string;
type NameOrResolver </span>= Name |<span style="color: rgba(0, 0, 0, 1)"> NameResolver;
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getName(n: NameOrResolver): Name {
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">typeof</span> n === 'string'<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)"> n;
    } </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)"> n();
    }
}</span></pre>
</div>
<p>上例中,我们使用&nbsp;<code>type</code>&nbsp;创建类型别名。</p>
<p>类型别名常用于联合类型。</p>
<h2>1.2、基本使用</h2>
<p>通过type可以定义类似接口的类型,如下示例中User是一个自定义的类型,tom被User约束:</p>
<div class="cnblogs_code">
<pre>type User=<span style="color: rgba(0, 0, 0, 1)">{
    name:string;
    age:number;
}
let tom:User</span>=<span style="color: rgba(0, 0, 0, 1)">{
    name: </span>"tom"<span style="color: rgba(0, 0, 0, 1)">,
    age: </span>18<span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<h2>1.2、联合使用</h2>
<div class="cnblogs_code">
<pre>type User=<span style="color: rgba(0, 0, 0, 1)">{
    name:string;
    age:number;
}
type Fly</span>=<span style="color: rgba(0, 0, 0, 1)">{
    fly():</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">;
}

type SuperMan</span>=User &amp;<span style="color: rgba(0, 0, 0, 1)"> Fly;

let superMan:SuperMan;

superMan</span>={name:"jack",age:20,fly:()=&gt;console.log("我会飞"<span style="color: rgba(0, 0, 0, 1)">)}
superMan.fly();

console.log(</span><span style="color: rgba(0, 0, 255, 1)">typeof</span>(superMan));</pre>
</div>
<p>运行结果:</p>
<p><img src="https://img2022.cnblogs.com/blog/63651/202209/63651-20220927140520333-389582386.png" alt="" width="480" height="63" loading="lazy"></p>
<h2>1.3、type与interface接口的相同点</h2>
<p>1.都可以用来描述一个对象或者函数</p>
<p>interface</p>
<div class="cnblogs_code">
<pre>interface user {name: string; age:number}; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 对象</span>
interface setUser {(name: string; age:number):<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></pre>
</div>
<p>type</p>
<div class="cnblogs_code">
<pre>type user = {name: string; age:number}; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 对象</span>
type setUser = (name: string; age:number):<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></pre>
</div>
<p>2.都可以进行拓展</p>
<p>interface可以扩展,type可以通过交叉实现interface的extends行为,interface可以extends type,同时type也可以与interface类型交叉 。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> interface通过extends实现继承</span>
<span style="color: rgba(0, 0, 0, 1)">interface userName {
name: string;
}
interface user extends userName {
age: number
}
let stu:user </span>= {name: 'wang', age: 10<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)"> interface的extends扩展可以通过type交叉(&amp;)类型实现</span>
type userName =<span style="color: rgba(0, 0, 0, 1)"> {
   name: string;
}
type user </span>= userName &amp;<span style="color: rgba(0, 0, 0, 1)"> {age: number}
let stu:user</span>={name: 'wang', age: 18<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)"> interface扩展type</span>
type name =<span style="color: rgba(0, 0, 0, 1)"> {
name: string;
}
interface user extends name {
age: number;
}
let stu:user</span>={name: 'wang', age: 89<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)"> type与interface交叉</span>
<span style="color: rgba(0, 0, 0, 1)">interface name {
name: string;
}
type user </span>= name &amp;<span style="color: rgba(0, 0, 0, 1)"> {
age: number;
}
let stu:user</span>={name:'wang', age: 18}</pre>
</div>
<p>3.在type中可以使用泛型,接口也可以使用泛型</p>
<div class="cnblogs_code">
<pre>type Zoo&lt;T&gt; =<span> T;
const num : Zoo&lt;number&gt; = 3<span>;

type callback&lt;T&gt; = (data: T) =&gt; void;</span></span></pre>
</div>
<h2>1.4、type与interface接口的不同点</h2>
<p>1.类型别名可以用于其它类型 (联合类型、元组类型、基本类型(原始值)),interface不支持</p>
<div class="cnblogs_code">
<pre>type Name=string;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">正确</span>
interface Num=number;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">错误</span></pre>
</div>
<p>2.interface 可以多次定义来合并声明,type 不支持</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface user {
    name: string;
    age: number;
}
interface user {
    sex: string;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">user实际接口为:</span>
<span style="color: rgba(0, 0, 0, 1)">{
    name: string;
    age: number;
    sex: string;
}</span></pre>
</div>
<p>3.type 能使用 in 关键字生成映射类型,但 interface 不行</p>
<div class="cnblogs_code">
<pre>type keys="name"|"sex"<span style="color: rgba(0, 0, 0, 1)">;

type User</span>=<span style="color: rgba(0, 0, 0, 1)">{
    :string;
}

let tom:User</span>={name:"tom",sex:"male"}</pre>
</div>
<p>4.默认导出方式不同</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> inerface 支持同时声明,默认导出 而type必须先声明后导出</span>
export <span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)"> interface name {
name: string;
};
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 同一个js模块只能存在一个默认导出</span>
type typeName =<span style="color: rgba(0, 0, 0, 1)"> {name: string};
export </span><span style="color: rgba(0, 0, 255, 1)">default</span> typeName</pre>
</div>
<p>5.type可以使用typeof获取实例类型</p>
<div class="cnblogs_code">
<pre>let div = document.createElement('div'<span style="color: rgba(0, 0, 0, 1)">);
type divType </span>= <span style="color: rgba(0, 0, 255, 1)">typeof</span> div;</pre>
</div>
<h1>二、字符串字面量类型</h1>
<p>字符串字面量类型用来约束取值只能是某几个字符串中的一个。</p>
<p id="%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%8B%E5%AD%90"><strong>简单的例子</strong><br></p>
<div class="cnblogs_code">
<pre>type EventNames = 'click' | 'scroll' | 'mousemove'<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> handleEvent(ele: Element, event: EventNames) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> do something</span>
<span style="color: rgba(0, 0, 0, 1)">}

handleEvent(document.getElementById(</span>'hello'), 'scroll');<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 没问题</span>
handleEvent(document.getElementById('world'), 'dblclick'); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 报错,event 不能为 'dblclick'</span>

<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> index.ts(7,47): error TS2345: Argument of type '"dblclick"' is not assignable to parameter of type 'EventNames'.</span></pre>
</div>
<p>上例中,我们使用&nbsp;<code>type</code>&nbsp;定了一个字符串字面量类型&nbsp;<code>EventNames</code>,它只能取三种字符串中的一种。</p>
<p>注意,类型别名与字符串字面量类型都是使用&nbsp;<code>type</code>&nbsp;进行定义。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">在定义变量时可以指定变量的类型为某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, 0, 0, 1)">
let age:</span>88;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">约束age的值只能是88</span>
<span style="color: rgba(0, 0, 0, 1)">
age</span>=88<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)">age=87.9;//错误</span>
<span style="color: rgba(0, 0, 0, 1)">
let sex:</span>"男"|"女";<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">sex只允许是男或女</span>
sex="男"<span style="color: rgba(0, 0, 0, 1)">;
sex</span>="女"<span style="color: rgba(0, 0, 0, 1)">;

let obj:{name:</span>"tom"}=<span style="color: rgba(0, 0, 0, 1)">{
    name:</span>"tom"<span style="color: rgba(0, 0, 0, 1)">
};</span></pre>
</div>
<h1>三、元组</h1>
<p>数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。</p>
<p>元组起源于函数编程语言(如 F#),这些语言中会频繁使用元组。</p>
<p id="%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%8B%E5%AD%90"><strong>简单的例子</strong><br></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">let tom<span class="token operator">: <span class="token punctuation">[<span class="token builtin">string<span class="token punctuation">, <span class="token builtin">number<span class="token punctuation">] <span class="token operator">= <span class="token punctuation">[<span class="token string">'Tom'<span class="token punctuation">, <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></code></pre>
<p>当赋值或访问一个已知索引的元素时,会得到正确的类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let tom<span class="token operator">: <span class="token punctuation">[<span class="token builtin">string<span class="token punctuation">, <span class="token builtin">number<span class="token punctuation">]<span class="token punctuation">;
tom<span class="token punctuation">[<span class="token number">0<span class="token punctuation">] <span class="token operator">= <span class="token string">'Tom'<span class="token punctuation">;
tom<span class="token punctuation">[<span class="token number">1<span class="token punctuation">] <span class="token operator">= <span class="token number">25<span class="token punctuation">;

tom<span class="token punctuation">[<span class="token number">0<span class="token punctuation">]<span class="token punctuation">.<span class="token function">slice<span class="token punctuation">(<span class="token number">1<span class="token punctuation">)<span class="token punctuation">;
tom<span class="token punctuation">[<span class="token number">1<span class="token punctuation">]<span class="token punctuation">.<span class="token function">toFixed<span class="token punctuation">(<span class="token number">2<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>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let tom<span class="token operator">: <span class="token punctuation">[<span class="token builtin">string<span class="token punctuation">, <span class="token builtin">number<span class="token punctuation">]<span class="token punctuation">;
tom<span class="token punctuation">[<span class="token number">0<span class="token punctuation">] <span class="token operator">= <span class="token string">'Tom'<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 tom<span class="token operator">: <span class="token punctuation">[<span class="token builtin">string<span class="token punctuation">, <span class="token builtin">number<span class="token punctuation">]<span class="token punctuation">;
tom <span class="token operator">= <span class="token punctuation">[<span class="token string">'Tom'<span class="token punctuation">, <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></code></pre>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let tom<span class="token operator">: <span class="token punctuation">[<span class="token builtin">string<span class="token punctuation">, <span class="token builtin">number<span class="token punctuation">]<span class="token punctuation">;
tom <span class="token operator">= <span class="token punctuation">[<span class="token string">'Tom'<span class="token punctuation">]<span class="token punctuation">;

<span class="token comment">// Property '1' is missing in type '' but required in type ''.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p id="%E8%B6%8A%E7%95%8C%E7%9A%84%E5%85%83%E7%B4%A0"><strong>越界的元素</strong><br></p>
<p>当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">let tom<span class="token operator">: <span class="token punctuation">[<span class="token builtin">string<span class="token punctuation">, <span class="token builtin">number<span class="token punctuation">]<span class="token punctuation">;
tom <span class="token operator">= <span class="token punctuation">[<span class="token string">'Tom'<span class="token punctuation">, <span class="token number">25<span class="token punctuation">]<span class="token punctuation">;
tom<span class="token punctuation">.<span class="token function">push<span class="token punctuation">(<span class="token string">'male'<span class="token punctuation">)<span class="token punctuation">;
tom<span class="token punctuation">.<span class="token function">push<span class="token punctuation">(<span class="token boolean">true<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>
<div>
<h1>四、枚举</h1>
<p>枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。</p>
<h2 id="%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%8B%E5%AD%90">4.1、简单的例子<br></h2>
<p>枚举使用&nbsp;<code>enum</code>&nbsp;关键字来定义:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">enum Days <span class="token punctuation">{Sun<span class="token punctuation">, Mon<span class="token punctuation">, Tue<span class="token punctuation">, Wed<span class="token punctuation">, Thu<span class="token punctuation">, Fri<span class="token punctuation">, Sat<span class="token punctuation">}<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></span></code></pre>
<p>枚举成员会被赋值为从&nbsp;<code>0</code>&nbsp;开始递增的数字,同时也会对枚举值到枚举名进行反向映射:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">enum Days <span class="token punctuation">{Sun<span class="token punctuation">, Mon<span class="token punctuation">, Tue<span class="token punctuation">, Wed<span class="token punctuation">, Thu<span class="token punctuation">, Fri<span class="token punctuation">, Sat<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">(Days<span class="token punctuation">[<span class="token string">"Sun"<span class="token punctuation">] <span class="token operator">=== <span class="token number">0<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token string">"Mon"<span class="token punctuation">] <span class="token operator">=== <span class="token number">1<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token string">"Tue"<span class="token punctuation">] <span class="token operator">=== <span class="token number">2<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token string">"Sat"<span class="token punctuation">] <span class="token operator">=== <span class="token number">6<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true

<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token number">0<span class="token punctuation">] <span class="token operator">=== <span class="token string">"Sun"<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token number">1<span class="token punctuation">] <span class="token operator">=== <span class="token string">"Mon"<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token number">2<span class="token punctuation">] <span class="token operator">=== <span class="token string">"Tue"<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token number">6<span class="token punctuation">] <span class="token operator">=== <span class="token string">"Sat"<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></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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 <span class="token maybe-class-name">Days<span class="token punctuation">;
<span class="token punctuation">(<span class="token keyword">function <span class="token punctuation">(<span class="token parameter"><span class="token maybe-class-name">Days<span class="token punctuation">) <span class="token punctuation">{
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Sun"<span class="token punctuation">] <span class="token operator">= <span class="token number">0<span class="token punctuation">] <span class="token operator">= <span class="token string">"Sun"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Mon"<span class="token punctuation">] <span class="token operator">= <span class="token number">1<span class="token punctuation">] <span class="token operator">= <span class="token string">"Mon"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Tue"<span class="token punctuation">] <span class="token operator">= <span class="token number">2<span class="token punctuation">] <span class="token operator">= <span class="token string">"Tue"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Wed"<span class="token punctuation">] <span class="token operator">= <span class="token number">3<span class="token punctuation">] <span class="token operator">= <span class="token string">"Wed"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Thu"<span class="token punctuation">] <span class="token operator">= <span class="token number">4<span class="token punctuation">] <span class="token operator">= <span class="token string">"Thu"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Fri"<span class="token punctuation">] <span class="token operator">= <span class="token number">5<span class="token punctuation">] <span class="token operator">= <span class="token string">"Fri"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Sat"<span class="token punctuation">] <span class="token operator">= <span class="token number">6<span class="token punctuation">] <span class="token operator">= <span class="token string">"Sat"<span class="token punctuation">;
<span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">(<span class="token maybe-class-name">Days <span class="token operator">|| <span class="token punctuation">(<span class="token maybe-class-name">Days <span class="token operator">= <span class="token punctuation">{<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></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 id="%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%8B%E5%AD%90">4.2、手动赋值</h2>
<p>我们也可以给枚举项手动赋值:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">enum Days <span class="token punctuation">{Sun <span class="token operator">= <span class="token number">7<span class="token punctuation">, Mon <span class="token operator">= <span class="token number">1<span class="token punctuation">, Tue<span class="token punctuation">, Wed<span class="token punctuation">, Thu<span class="token punctuation">, Fri<span class="token punctuation">, Sat<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">(Days<span class="token punctuation">[<span class="token string">"Sun"<span class="token punctuation">] <span class="token operator">=== <span class="token number">7<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token string">"Mon"<span class="token punctuation">] <span class="token operator">=== <span class="token number">1<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token string">"Tue"<span class="token punctuation">] <span class="token operator">=== <span class="token number">2<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token string">"Sat"<span class="token punctuation">] <span class="token operator">=== <span class="token number">6<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></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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>如果未手动赋值的枚举项与手动赋值的重复了,TypeScript 是不会察觉到这一点的:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">enum Days <span class="token punctuation">{Sun <span class="token operator">= <span class="token number">3<span class="token punctuation">, Mon <span class="token operator">= <span class="token number">1<span class="token punctuation">, Tue<span class="token punctuation">, Wed<span class="token punctuation">, Thu<span class="token punctuation">, Fri<span class="token punctuation">, Sat<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">(Days<span class="token punctuation">[<span class="token string">"Sun"<span class="token punctuation">] <span class="token operator">=== <span class="token number">3<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token string">"Wed"<span class="token punctuation">] <span class="token operator">=== <span class="token number">3<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token number">3<span class="token punctuation">] <span class="token operator">=== <span class="token string">"Sun"<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// false
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token number">3<span class="token punctuation">] <span class="token operator">=== <span class="token string">"Wed"<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></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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>3</code>&nbsp;的时候与前面的&nbsp;<code>Sun</code>&nbsp;的取值重复了,但是 TypeScript 并没有报错,导致&nbsp;<code>Days</code>&nbsp;的值先是&nbsp;<code>"Sun"</code>,而后又被&nbsp;<code>"Wed"</code>&nbsp;覆盖了。编译的结果是:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var <span class="token maybe-class-name">Days<span class="token punctuation">;
<span class="token punctuation">(<span class="token keyword">function <span class="token punctuation">(<span class="token parameter"><span class="token maybe-class-name">Days<span class="token punctuation">) <span class="token punctuation">{
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Sun"<span class="token punctuation">] <span class="token operator">= <span class="token number">3<span class="token punctuation">] <span class="token operator">= <span class="token string">"Sun"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Mon"<span class="token punctuation">] <span class="token operator">= <span class="token number">1<span class="token punctuation">] <span class="token operator">= <span class="token string">"Mon"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Tue"<span class="token punctuation">] <span class="token operator">= <span class="token number">2<span class="token punctuation">] <span class="token operator">= <span class="token string">"Tue"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Wed"<span class="token punctuation">] <span class="token operator">= <span class="token number">3<span class="token punctuation">] <span class="token operator">= <span class="token string">"Wed"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Thu"<span class="token punctuation">] <span class="token operator">= <span class="token number">4<span class="token punctuation">] <span class="token operator">= <span class="token string">"Thu"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Fri"<span class="token punctuation">] <span class="token operator">= <span class="token number">5<span class="token punctuation">] <span class="token operator">= <span class="token string">"Fri"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Sat"<span class="token punctuation">] <span class="token operator">= <span class="token number">6<span class="token punctuation">] <span class="token operator">= <span class="token string">"Sat"<span class="token punctuation">;
<span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">(<span class="token maybe-class-name">Days <span class="token operator">|| <span class="token punctuation">(<span class="token maybe-class-name">Days <span class="token operator">= <span class="token punctuation">{<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></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>所以使用的时候需要注意,最好不要出现这种覆盖的情况。</p>
<p>手动赋值的枚举项可以不是数字,此时需要使用类型断言来让 tsc 无视类型检查 (编译出的 js 仍然是可用的):</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">enum Days <span class="token punctuation">{Sun <span class="token operator">= <span class="token number">7<span class="token punctuation">, Mon<span class="token punctuation">, Tue<span class="token punctuation">, Wed<span class="token punctuation">, Thu<span class="token punctuation">, Fri<span class="token punctuation">, Sat <span class="token operator">= <span class="token operator">&lt;<span class="token builtin">any<span class="token operator">&gt;<span class="token string">"S"<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>
<pre class="language-js"><code class="language-js"><span class="token keyword">var <span class="token maybe-class-name">Days<span class="token punctuation">;
<span class="token punctuation">(<span class="token keyword">function <span class="token punctuation">(<span class="token parameter"><span class="token maybe-class-name">Days<span class="token punctuation">) <span class="token punctuation">{
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Sun"<span class="token punctuation">] <span class="token operator">= <span class="token number">7<span class="token punctuation">] <span class="token operator">= <span class="token string">"Sun"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Mon"<span class="token punctuation">] <span class="token operator">= <span class="token number">8<span class="token punctuation">] <span class="token operator">= <span class="token string">"Mon"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Tue"<span class="token punctuation">] <span class="token operator">= <span class="token number">9<span class="token punctuation">] <span class="token operator">= <span class="token string">"Tue"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Wed"<span class="token punctuation">] <span class="token operator">= <span class="token number">10<span class="token punctuation">] <span class="token operator">= <span class="token string">"Wed"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Thu"<span class="token punctuation">] <span class="token operator">= <span class="token number">11<span class="token punctuation">] <span class="token operator">= <span class="token string">"Thu"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Fri"<span class="token punctuation">] <span class="token operator">= <span class="token number">12<span class="token punctuation">] <span class="token operator">= <span class="token string">"Fri"<span class="token punctuation">;
    <span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token maybe-class-name">Days<span class="token punctuation">[<span class="token string">"Sat"<span class="token punctuation">] <span class="token operator">= <span class="token string">"S"<span class="token punctuation">] <span class="token operator">= <span class="token string">"Sat"<span class="token punctuation">;
<span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">(<span class="token maybe-class-name">Days <span class="token operator">|| <span class="token punctuation">(<span class="token maybe-class-name">Days <span class="token operator">= <span class="token punctuation">{<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></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>当然,手动赋值的枚举项也可以为小数或负数,此时后续未手动赋值的项的递增步长仍为&nbsp;<code>1</code>:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">enum Days <span class="token punctuation">{Sun <span class="token operator">= <span class="token number">7<span class="token punctuation">, Mon <span class="token operator">= <span class="token number">1.5<span class="token punctuation">, Tue<span class="token punctuation">, Wed<span class="token punctuation">, Thu<span class="token punctuation">, Fri<span class="token punctuation">, Sat<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">(Days<span class="token punctuation">[<span class="token string">"Sun"<span class="token punctuation">] <span class="token operator">=== <span class="token number">7<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token string">"Mon"<span class="token punctuation">] <span class="token operator">=== <span class="token number">1.5<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token string">"Tue"<span class="token punctuation">] <span class="token operator">=== <span class="token number">2.5<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(Days<span class="token punctuation">[<span class="token string">"Sat"<span class="token punctuation">] <span class="token operator">=== <span class="token number">6.5<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></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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="%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%8B%E5%AD%90">4.3、常数项和计算所得项<br></h2>
<p>枚举项有两种类型:常数项(constant member)和计算所得项(computed member)。</p>
<p>前面我们所举的例子都是常数项,一个典型的计算所得项的例子:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">enum Color <span class="token punctuation">{Red<span class="token punctuation">, Green<span class="token punctuation">, Blue <span class="token operator">= <span class="token string">"blue"<span class="token punctuation">.length<span class="token punctuation">}<span class="token punctuation">;
</span></span></span></span></span></span></span></span></span></code></pre>
<p>上面的例子中,<code>"blue".length</code>&nbsp;就是一个计算所得项。</p>
<p>上面的例子不会报错,但是如果紧接在计算所得项后面的是未手动赋值的项,那么它就会因为无法获得初始值而报错:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">enum Color <span class="token punctuation">{Red <span class="token operator">= <span class="token string">"red"<span class="token punctuation">.length<span class="token punctuation">, Green<span class="token punctuation">, Blue<span class="token punctuation">}<span class="token punctuation">;

<span class="token comment">// index.ts(1,33): error TS1061: Enum member must have initializer.
<span class="token comment">// index.ts(1,40): error TS1061: Enum member must have initializer.
</span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>下面是常数项和计算所得项的完整定义,部分引用自中文手册 - 枚举:</p>
<p>当满足以下条件时,枚举成员被当作是常数:</p>
<ul>
<li>不具有初始化函数并且之前的枚举成员是常数。在这种情况下,当前枚举成员的值为上一个枚举成员的值加&nbsp;<code>1</code>。但第一个枚举元素是个例外。如果它没有初始化方法,那么它的初始值为&nbsp;<code>0</code>。</li>
<li>枚举成员使用常数枚举表达式初始化。常数枚举表达式是 TypeScript 表达式的子集,它可以在编译阶段求值。当一个表达式满足下面条件之一时,它就是一个常数枚举表达式:
<ul>
<li>数字字面量</li>
<li>引用之前定义的常数枚举成员(可以是在不同的枚举类型中定义的)如果这个成员是在同一个枚举类型中定义的,可以使用非限定名来引用</li>
<li>带括号的常数枚举表达式</li>
<li><code>+</code>,&nbsp;<code>-</code>,&nbsp;<code>~</code>&nbsp;一元运算符应用于常数枚举表达式</li>
<li><code>+</code>,&nbsp;<code>-</code>,&nbsp;<code>*</code>,&nbsp;<code>/</code>,&nbsp;<code>%</code>,&nbsp;<code>&lt;&lt;</code>,&nbsp;<code>&gt;&gt;</code>,&nbsp;<code>&gt;&gt;&gt;</code>,&nbsp;<code>&amp;</code>,&nbsp;<code>|</code>,&nbsp;<code>^</code>&nbsp;二元运算符,常数枚举表达式做为其一个操作对象。若常数枚举表达式求值后为 NaN 或 Infinity,则会在编译阶段报错</li>
</ul>
</li>
</ul>
<p>所有其它情况的枚举成员被当作是需要计算得出的值。</p>
<h2 id="%E5%B8%B8%E6%95%B0%E6%9E%9A%E4%B8%BE">4.4、常数枚举<br></h2>
<p>常数枚举是使用&nbsp;<code>const enum</code>&nbsp;定义的枚举类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">const <span class="token keyword">enum Directions <span class="token punctuation">{
    Up<span class="token punctuation">,
    Down<span class="token punctuation">,
    Left<span class="token punctuation">,
    Right
<span class="token punctuation">}

<span class="token keyword">let directions <span class="token operator">= <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>
<p>上例的编译结果是:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var directions <span class="token operator">= <span class="token punctuation">[<span class="token number">0 <span class="token comment">/* Up */<span class="token punctuation">, <span class="token number">1 <span class="token comment">/* Down */<span class="token punctuation">, <span class="token number">2 <span class="token comment">/* Left */<span class="token punctuation">, <span class="token number">3 <span class="token comment">/* Right */<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">const <span class="token keyword">enum Color <span class="token punctuation">{Red<span class="token punctuation">, Green<span class="token punctuation">, Blue <span class="token operator">= <span class="token string">"blue"<span class="token punctuation">.length<span class="token punctuation">}<span class="token punctuation">;

<span class="token comment">// index.ts(1,38): error TS2474: In 'const' enum declarations member initializer must be constant expression.
</span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 id="%E5%A4%96%E9%83%A8%E6%9E%9A%E4%B8%BE">4.5、外部枚举<br></h2>
<p>外部枚举(Ambient Enums)是使用&nbsp;<code>declare enum</code>&nbsp;定义的枚举类型:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">declare <span class="token keyword">enum Directions <span class="token punctuation">{
    Up<span class="token punctuation">,
    Down<span class="token punctuation">,
    Left<span class="token punctuation">,
    Right
<span class="token punctuation">}

<span class="token keyword">let directions <span class="token operator">= <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>之前提到过,<code>declare</code>&nbsp;定义的类型只会用于编译时的检查,编译结果中会被删除。</p>
<p>上例的编译结果是:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var directions <span class="token operator">= <span class="token punctuation">[<span class="token maybe-class-name">Directions<span class="token punctuation">.<span class="token property-access"><span class="token maybe-class-name">Up<span class="token punctuation">, <span class="token maybe-class-name">Directions<span class="token punctuation">.<span class="token property-access"><span class="token maybe-class-name">Down<span class="token punctuation">, <span class="token maybe-class-name">Directions<span class="token punctuation">.<span class="token property-access"><span class="token maybe-class-name">Left<span class="token punctuation">, <span class="token maybe-class-name">Directions<span class="token punctuation">.<span class="token property-access"><span class="token maybe-class-name">Right<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></code></pre>
<p>外部枚举与声明语句一样,常出现在声明文件中。</p>
<p>同时使用&nbsp;<code>declare</code>&nbsp;和&nbsp;<code>const</code>&nbsp;也是可以的:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">declare <span class="token keyword">const <span class="token keyword">enum Directions <span class="token punctuation">{
    Up<span class="token punctuation">,
    Down<span class="token punctuation">,
    Left<span class="token punctuation">,
    Right
<span class="token punctuation">}

<span class="token keyword">let directions <span class="token operator">= <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></code></pre>
<p>编译结果:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var directions <span class="token operator">= <span class="token punctuation">[<span class="token number">0 <span class="token comment">/* Up */<span class="token punctuation">, <span class="token number">1 <span class="token comment">/* Down */<span class="token punctuation">, <span class="token number">2 <span class="token comment">/* Left */<span class="token punctuation">, <span class="token number">3 <span class="token comment">/* Right */<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>
<blockquote>
<p>TypeScript 的枚举类型的概念来源于 C#。</p>
</blockquote>
</div>
<h1>五、类</h1>
<p>传统方法中,JavaScript 通过构造函数实现类的概念,通过原型链实现继承。而在 ES6 中,我们终于迎来了&nbsp;<code>class</code>。</p>
<p>TypeScript 除了实现了所有 ES6 中的类的功能以外,还添加了一些新的用法。</p>
<p>这一节主要介绍类的用法,下一节再介绍如何定义类的类型。</p>
<h2 id="%E7%B1%BB%E7%9A%84%E6%A6%82%E5%BF%B5">5.1、类的概念<br></h2>
<p>虽然 JavaScript 中有类的概念,但是可能大多数 JavaScript 程序员并不是非常熟悉类,这里对类相关的概念做一个简单的介绍。</p>
<ul>
<li>类(Class):定义了一件事物的抽象特点,包含它的属性和方法</li>
<li>对象(Object):类的实例,通过&nbsp;<code>new</code>&nbsp;生成</li>
<li>面向对象(OOP)的三大特性:封装、继承、多态</li>
<li>封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据</li>
<li>继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性</li>
<li>多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比如&nbsp;<code>Cat</code>&nbsp;和&nbsp;<code>Dog</code>&nbsp;都继承自&nbsp;<code>Animal</code>,但是分别实现了自己的&nbsp;<code>eat</code>&nbsp;方法。此时针对某一个实例,我们无需了解它是&nbsp;<code>Cat</code>&nbsp;还是&nbsp;<code>Dog</code>,就可以直接调用&nbsp;<code>eat</code>&nbsp;方法,程序会自动判断出来应该如何执行&nbsp;<code>eat</code></li>
<li>存取器(getter &amp; setter):用以改变属性的读取和赋值行为</li>
<li>修饰符(Modifiers):修饰符是一些关键字,用于限定成员或类型的性质。比如&nbsp;<code>public</code>&nbsp;表示公有属性或方法</li>
<li>抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现</li>
<li>接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现(implements)。一个类只能继承自另一个类,但是可以实现多个接口</li>









</ul>
<h2 id="es6-%E4%B8%AD%E7%B1%BB%E7%9A%84%E7%94%A8%E6%B3%95">5.2、ES6 中类的用法<br></h2>
<p>下面我们先回顾一下 ES6 中类的用法,更详细的介绍可以参考&nbsp;ECMAScript 6 入门 - Class。</p>
<p id="%E5%B1%9E%E6%80%A7%E5%92%8C%E6%96%B9%E6%B3%95"><strong>属性和方法</strong><br></p>
<p>使用&nbsp;<code>class</code>&nbsp;定义类,使用&nbsp;<code>constructor</code>&nbsp;定义构造函数。</p>
<p>通过&nbsp;<code>new</code>&nbsp;生成新实例的时候,会自动调用构造函数。</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
    <span class="token keyword">public name<span class="token punctuation">;
    <span class="token function">constructor<span class="token punctuation">(<span class="token parameter">name<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">this<span class="token punctuation">.<span class="token property-access">name <span class="token operator">= name<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token function">sayHi<span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword control-flow">return <span class="token template-string"><span class="token template-punctuation string">`<span class="token string">My name is <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${<span class="token keyword">this<span class="token punctuation">.<span class="token property-access">name<span class="token interpolation-punctuation punctuation">}<span class="token template-punctuation string">`<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 keyword">new <span class="token class-name">Animal<span class="token punctuation">(<span class="token string">'Jack'<span class="token punctuation">)<span class="token punctuation">;
<span class="token console class-name">console<span class="token punctuation">.<span class="token method function property-access">log<span class="token punctuation">(a<span class="token punctuation">.<span class="token method function property-access">sayHi<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// My name is Jack
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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 id="%E7%B1%BB%E7%9A%84%E7%BB%A7%E6%89%BF"><strong>类的继承</strong><br></p>
<p>使用&nbsp;<code>extends</code>&nbsp;关键字实现继承,子类中使用&nbsp;<code>super</code>&nbsp;关键字来调用父类的构造函数和方法。</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class <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">constructor<span class="token punctuation">(<span class="token parameter">name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">super<span class="token punctuation">(name<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// 调用父类的 constructor(name)
    <span class="token console class-name">console<span class="token punctuation">.<span class="token method function property-access">log<span class="token punctuation">(<span class="token keyword">this<span class="token punctuation">.<span class="token property-access">name<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}
<span class="token function">sayHi<span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword control-flow">return <span class="token string">'Meow, ' <span class="token operator">+ <span class="token keyword">super<span class="token punctuation">.<span class="token method function property-access">sayHi<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// 调用父类的 sayHi()
<span class="token punctuation">}
<span class="token punctuation">}

<span class="token keyword">let c <span class="token operator">= <span class="token keyword">new <span class="token class-name">Cat<span class="token punctuation">(<span class="token string">'Tom'<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// Tom
<span class="token console class-name">console<span class="token punctuation">.<span class="token method function property-access">log<span class="token punctuation">(c<span class="token punctuation">.<span class="token method function property-access">sayHi<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// Meow, My name is Tom
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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 id="%E5%AD%98%E5%8F%96%E5%99%A8"><strong>存取器</strong><br></p>
<p>使用 getter 和 setter 可以改变属性的赋值和读取行为:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token function">constructor<span class="token punctuation">(<span class="token parameter">name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.<span class="token property-access">name <span class="token operator">= name<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">get <span class="token function">name<span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword control-flow">return <span class="token string">'Jack'<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">set <span class="token function">name<span class="token punctuation">(<span class="token parameter">value<span class="token punctuation">) <span class="token punctuation">{
    <span class="token console class-name">console<span class="token punctuation">.<span class="token method function property-access">log<span class="token punctuation">(<span class="token string">'setter: ' <span class="token operator">+ value<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 keyword">new <span class="token class-name">Animal<span class="token punctuation">(<span class="token string">'Kitty'<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// setter: Kitty
a<span class="token punctuation">.<span class="token property-access">name <span class="token operator">= <span class="token string">'Tom'<span class="token punctuation">; <span class="token comment">// setter: Tom
<span class="token console class-name">console<span class="token punctuation">.<span class="token method function property-access">log<span class="token punctuation">(a<span class="token punctuation">.<span class="token property-access">name<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// Jack
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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 id="%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95"><strong>静态方法</strong><br></p>
<p>使用&nbsp;<code>static</code>&nbsp;修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">static <span class="token function">isAnimal<span class="token punctuation">(<span class="token parameter">a<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword control-flow">return a <span class="token keyword">instanceof <span class="token class-name">Animal<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 keyword">new <span class="token class-name">Animal<span class="token punctuation">(<span class="token string">'Jack'<span class="token punctuation">)<span class="token punctuation">;
<span class="token maybe-class-name">Animal<span class="token punctuation">.<span class="token method function property-access">isAnimal<span class="token punctuation">(a<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// true
a<span class="token punctuation">.<span class="token method function property-access">isAnimal<span class="token punctuation">(a<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// TypeError: a.isAnimal 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></code></pre>
<h2 id="es7-%E4%B8%AD%E7%B1%BB%E7%9A%84%E7%94%A8%E6%B3%95">5.3、ES7 中类的用法<br></h2>
<p>ES7 中有一些关于类的提案,TypeScript 也实现了它们,这里做一个简单的介绍。</p>
<p id="%E5%AE%9E%E4%BE%8B%E5%B1%9E%E6%80%A7"><strong>实例属性</strong><br></p>
<p>ES6 中实例的属性只能通过构造函数中的&nbsp;<code>this.xxx</code>&nbsp;来定义,ES7 提案中可以直接在类里面定义:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
name <span class="token operator">= <span class="token string">'Jack'<span class="token punctuation">;

<span class="token function">constructor<span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
    <span class="token comment">// ...
<span class="token punctuation">}
<span class="token punctuation">}

<span class="token keyword">let a <span class="token operator">= <span class="token keyword">new <span class="token class-name">Animal<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;
<span class="token console class-name">console<span class="token punctuation">.<span class="token method function property-access">log<span class="token punctuation">(a<span class="token punctuation">.<span class="token property-access">name<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// Jack
</span></span></span></span></span></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 id="%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7"><strong>静态属性</strong><br></p>
<p>ES7 提案中,可以使用&nbsp;<code>static</code>&nbsp;定义一个静态属性:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">static num <span class="token operator">= <span class="token number">42<span class="token punctuation">;

<span class="token function">constructor<span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
    <span class="token comment">// ...
<span class="token punctuation">}
<span class="token punctuation">}

<span class="token console class-name">console<span class="token punctuation">.<span class="token method function property-access">log<span class="token punctuation">(<span class="token maybe-class-name">Animal<span class="token punctuation">.<span class="token property-access">num<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// 42
</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="typescript-%E4%B8%AD%E7%B1%BB%E7%9A%84%E7%94%A8%E6%B3%95">5.4、TypeScript 中类的用法<br></h2>
<p id="public-private-%E5%92%8C-protected"><strong>public private 和 protected</strong><br></p>
<p>TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是&nbsp;<code>public</code>、<code>private</code>&nbsp;和&nbsp;<code>protected</code>。</p>
<ul>
<li><code>public</code>&nbsp;修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是&nbsp;<code>public</code>&nbsp;的</li>
<li><code>private</code>&nbsp;修饰的属性或方法是私有的,不能在声明它的类的外部访问</li>
<li><code>protected</code>&nbsp;修饰的属性或方法是受保护的,它和&nbsp;<code>private</code>&nbsp;类似,区别是它在子类中也是允许被访问的</li>









</ul>
<p>下面举一些例子:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">public name<span class="token punctuation">;
<span class="token keyword">public <span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.name <span class="token operator">= name<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 keyword">new <span class="token class-name">Animal<span class="token punctuation">(<span class="token string">'Jack'<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">(a<span class="token punctuation">.name<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// Jack
a<span class="token punctuation">.name <span class="token operator">= <span class="token string">'Tom'<span class="token punctuation">;
<span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(a<span class="token punctuation">.name<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// Tom
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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>name</code>&nbsp;被设置为了&nbsp;<code>public</code>,所以直接访问实例的&nbsp;<code>name</code>&nbsp;属性是允许的。</p>
<p>很多时候,我们希望有的属性是无法直接存取的,这时候就可以用&nbsp;<code>private</code>&nbsp;了:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">private name<span class="token punctuation">;
<span class="token keyword">public <span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.name <span class="token operator">= name<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 keyword">new <span class="token class-name">Animal<span class="token punctuation">(<span class="token string">'Jack'<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">(a<span class="token punctuation">.name<span class="token punctuation">)<span class="token punctuation">;
a<span class="token punctuation">.name <span class="token operator">= <span class="token string">'Tom'<span class="token punctuation">;

<span class="token comment">// index.ts(9,13): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
<span class="token comment">// index.ts(10,1): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
</span></span></span></span></span></span></span></span></span></span></span></span></span></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>private</code>&nbsp;属性在外部的可访问性。</p>
<p>上面的例子编译后的代码是:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var <span class="token maybe-class-name">Animal <span class="token operator">= <span class="token punctuation">(<span class="token keyword">function <span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
<span class="token keyword">function <span class="token function"><span class="token maybe-class-name">Animal<span class="token punctuation">(<span class="token parameter">name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.<span class="token property-access">name <span class="token operator">= name<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword control-flow">return <span class="token maybe-class-name">Animal<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">var a <span class="token operator">= <span class="token keyword">new <span class="token class-name">Animal<span class="token punctuation">(<span class="token string">'Jack'<span class="token punctuation">)<span class="token punctuation">;
<span class="token console class-name">console<span class="token punctuation">.<span class="token method function property-access">log<span class="token punctuation">(a<span class="token punctuation">.<span class="token property-access">name<span class="token punctuation">)<span class="token punctuation">;
a<span class="token punctuation">.<span class="token property-access">name <span class="token operator">= <span class="token string">'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></span></span></span></span></code></pre>
<p>使用&nbsp;<code>private</code>&nbsp;修饰的属性或方法,在子类中也是不允许访问的:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">private name<span class="token punctuation">;
<span class="token keyword">public <span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.name <span class="token operator">= name<span class="token punctuation">;
<span class="token punctuation">}
<span class="token punctuation">}

<span class="token keyword">class <span class="token class-name">Cat <span class="token keyword">extends <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">super<span class="token punctuation">(name<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 keyword">this<span class="token punctuation">.name<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}
<span class="token punctuation">}

<span class="token comment">// index.ts(11,17): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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>protected</code>&nbsp;修饰,则允许在子类中访问:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">protected name<span class="token punctuation">;
<span class="token keyword">public <span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.name <span class="token operator">= name<span class="token punctuation">;
<span class="token punctuation">}
<span class="token punctuation">}

<span class="token keyword">class <span class="token class-name">Cat <span class="token keyword">extends <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">super<span class="token punctuation">(name<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 keyword">this<span class="token punctuation">.name<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></code></pre>
<p>当构造函数修饰为&nbsp;<code>private</code>&nbsp;时,该类不允许被继承或者实例化:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">public name<span class="token punctuation">;
<span class="token keyword">private <span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.name <span class="token operator">= name<span class="token punctuation">;
<span class="token punctuation">}
<span class="token punctuation">}
<span class="token keyword">class <span class="token class-name">Cat <span class="token keyword">extends <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">super<span class="token punctuation">(name<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 keyword">new <span class="token class-name">Animal<span class="token punctuation">(<span class="token string">'Jack'<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// index.ts(7,19): TS2675: Cannot extend a class 'Animal'. Class constructor is marked as private.
<span class="token comment">// index.ts(13,9): TS2673: Constructor of class 'Animal' is private and only accessible within the class declaration.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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>protected</code>&nbsp;时,该类只允许被继承:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">public name<span class="token punctuation">;
<span class="token keyword">protected <span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.name <span class="token operator">= name<span class="token punctuation">;
<span class="token punctuation">}
<span class="token punctuation">}
<span class="token keyword">class <span class="token class-name">Cat <span class="token keyword">extends <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">super<span class="token punctuation">(name<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 keyword">new <span class="token class-name">Animal<span class="token punctuation">(<span class="token string">'Jack'<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// index.ts(13,9): TS2674: Constructor of class 'Animal' is protected and only accessible within the class declaration.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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 id="%E5%8F%82%E6%95%B0%E5%B1%9E%E6%80%A7"><strong>参数属性</strong><br></p>
<p>修饰符和<code>readonly</code>还可以使用在构造函数参数中,等同于类中定义该属性同时给该属性赋值,使代码更简洁。</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token comment">// public name: string;
<span class="token keyword">public <span class="token keyword">constructor<span class="token punctuation">(<span class="token keyword">public name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token comment">// this.name = name;
<span class="token punctuation">}
<span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p id="readonly"><strong>readonly</strong><br></p>
<p>只读属性关键字,只允许出现在属性声明或索引签名或构造函数中。</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">readonly name<span class="token punctuation">;
<span class="token keyword">public <span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.name <span class="token operator">= name<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 keyword">new <span class="token class-name">Animal<span class="token punctuation">(<span class="token string">'Jack'<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">(a<span class="token punctuation">.name<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// Jack
a<span class="token punctuation">.name <span class="token operator">= <span class="token string">'Tom'<span class="token punctuation">;

<span class="token comment">// index.ts(10,3): TS2540: Cannot assign to 'name' because it is 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></code></pre>
<p>注意如果&nbsp;<code>readonly</code>&nbsp;和其他访问修饰符同时存在的话,需要写在其后面。</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token comment">// public readonly name;
<span class="token keyword">public <span class="token keyword">constructor<span class="token punctuation">(<span class="token keyword">public <span class="token keyword">readonly name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token comment">// this.name = name;
<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 id="%E6%8A%BD%E8%B1%A1%E7%B1%BB"><strong>抽象类</strong><br></p>
<p><code>abstract</code>&nbsp;用于定义抽象类和其中的抽象方法。</p>
<p>什么是抽象类?</p>
<p>首先,抽象类是不允许被实例化的:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">abstract <span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">public name<span class="token punctuation">;
<span class="token keyword">public <span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.name <span class="token operator">= name<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">public <span class="token keyword">abstract <span class="token function">sayHi<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 keyword">new <span class="token class-name">Animal<span class="token punctuation">(<span class="token string">'Jack'<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// index.ts(9,11): error TS2511: Cannot create an instance of the abstract class 'Animal'.
</span></span></span></span></span></span></span></span></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;<code>sayHi</code>。在实例化抽象类的时候报错了。</p>
<p>其次,抽象类中的抽象方法必须被子类实现:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">abstract <span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">public name<span class="token punctuation">;
<span class="token keyword">public <span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.name <span class="token operator">= name<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">public <span class="token keyword">abstract <span class="token function">sayHi<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">class <span class="token class-name">Cat <span class="token keyword">extends <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">public <span class="token function">eat<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 template-string"><span class="token template-punctuation string">`<span class="token interpolation"><span class="token interpolation-punctuation punctuation">${<span class="token keyword">this<span class="token punctuation">.name<span class="token interpolation-punctuation punctuation">}<span class="token string"> is eating.<span class="token template-punctuation string">`<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}
<span class="token punctuation">}

<span class="token keyword">let cat <span class="token operator">= <span class="token keyword">new <span class="token class-name">Cat<span class="token punctuation">(<span class="token string">'Tom'<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// index.ts(9,7): error TS2515: Non-abstract class 'Cat' does not implement inherited abstract member 'sayHi' from class 'Animal'.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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</code>&nbsp;继承了抽象类&nbsp;<code>Animal</code>,但是没有实现抽象方法&nbsp;<code>sayHi</code>,所以编译报错了。</p>
<p>下面是一个正确使用抽象类的例子:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">abstract <span class="token keyword">class <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">public name<span class="token punctuation">;
<span class="token keyword">public <span class="token keyword">constructor<span class="token punctuation">(name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.name <span class="token operator">= name<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword">public <span class="token keyword">abstract <span class="token function">sayHi<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">class <span class="token class-name">Cat <span class="token keyword">extends <span class="token class-name">Animal <span class="token punctuation">{
<span class="token keyword">public <span class="token function">sayHi<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 template-string"><span class="token template-punctuation string">`<span class="token string">Meow, My name is <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${<span class="token keyword">this<span class="token punctuation">.name<span class="token interpolation-punctuation punctuation">}<span class="token template-punctuation string">`<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}
<span class="token punctuation">}

<span class="token keyword">let cat <span class="token operator">= <span class="token keyword">new <span class="token class-name">Cat<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></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>上面的例子中,我们实现了抽象方法&nbsp;<code>sayHi</code>,编译通过了。</p>
<p>需要注意的是,即使是抽象方法,TypeScript 的编译结果中,仍然会存在这个类,上面的代码的编译结果是:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var __extends <span class="token operator">=
<span class="token punctuation">(<span class="token keyword">this <span class="token operator">&amp;&amp; <span class="token keyword">this<span class="token punctuation">.<span class="token property-access">__extends<span class="token punctuation">) <span class="token operator">||
<span class="token keyword">function <span class="token punctuation">(<span class="token parameter">d<span class="token punctuation">, b<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword control-flow">for <span class="token punctuation">(<span class="token keyword">var p <span class="token keyword">in b<span class="token punctuation">) <span class="token keyword control-flow">if <span class="token punctuation">(b<span class="token punctuation">.<span class="token method function property-access">hasOwnProperty<span class="token punctuation">(p<span class="token punctuation">)<span class="token punctuation">) d<span class="token punctuation"> <span class="token operator">= b<span class="token punctuation"><span class="token punctuation">;
    <span class="token keyword">function <span class="token function">__<span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
      <span class="token keyword">this<span class="token punctuation">.<span class="token property-access">constructor <span class="token operator">= d<span class="token punctuation">;
    <span class="token punctuation">}
    d<span class="token punctuation">.<span class="token property-access">prototype <span class="token operator">= b <span class="token operator">=== <span class="token keyword null nil">null <span class="token operator">? <span class="token known-class-name class-name">Object<span class="token punctuation">.<span class="token method function property-access">create<span class="token punctuation">(b<span class="token punctuation">) <span class="token operator">: <span class="token punctuation">(<span class="token punctuation">(<span class="token class-name">__<span class="token punctuation">.<span class="token property-access">prototype <span class="token operator">= b<span class="token punctuation">.<span class="token property-access">prototype<span class="token punctuation">)<span class="token punctuation">, <span class="token keyword">new <span class="token class-name">__<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">var <span class="token maybe-class-name">Animal <span class="token operator">= <span class="token punctuation">(<span class="token keyword">function <span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
<span class="token keyword">function <span class="token function"><span class="token maybe-class-name">Animal<span class="token punctuation">(<span class="token parameter">name<span class="token punctuation">) <span class="token punctuation">{
    <span class="token keyword">this<span class="token punctuation">.<span class="token property-access">name <span class="token operator">= name<span class="token punctuation">;
<span class="token punctuation">}
<span class="token keyword control-flow">return <span class="token maybe-class-name">Animal<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">var <span class="token maybe-class-name">Cat <span class="token operator">= <span class="token punctuation">(<span class="token keyword">function <span class="token punctuation">(<span class="token parameter">_super<span class="token punctuation">) <span class="token punctuation">{
<span class="token function">__extends<span class="token punctuation">(<span class="token maybe-class-name">Cat<span class="token punctuation">, _super<span class="token punctuation">)<span class="token punctuation">;
<span class="token keyword">function <span class="token function"><span class="token maybe-class-name">Cat<span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
    _super<span class="token punctuation">.<span class="token method function property-access">apply<span class="token punctuation">(<span class="token keyword">this<span class="token punctuation">, arguments<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}
<span class="token class-name">Cat<span class="token punctuation">.<span class="token property-access">prototype<span class="token punctuation">.<span class="token method-variable function-variable method function property-access">sayHi <span class="token operator">= <span class="token keyword">function <span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{
    <span class="token console class-name">console<span class="token punctuation">.<span class="token method function property-access">log<span class="token punctuation">(<span class="token string">'Meow, My name is ' <span class="token operator">+ <span class="token keyword">this<span class="token punctuation">.<span class="token property-access">name<span class="token punctuation">)<span class="token punctuation">;
<span class="token punctuation">}<span class="token punctuation">;
<span class="token keyword control-flow">return <span class="token maybe-class-name">Cat<span class="token punctuation">;
<span class="token punctuation">}<span class="token punctuation">)<span class="token punctuation">(<span class="token maybe-class-name">Animal<span class="token punctuation">)<span class="token punctuation">;
<span class="token keyword">var cat <span class="token operator">= <span class="token keyword">new <span class="token class-name">Cat<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></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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="%E7%B1%BB%E7%9A%84%E7%B1%BB%E5%9E%8B">5.5、类的类型<br></h2>
<p>给类加上 TypeScript 的类型很简单,与接口类似:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <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 keyword">constructor<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">this<span class="token punctuation">.name <span class="token operator">= name<span class="token punctuation">;
<span class="token punctuation">}
<span class="token function">sayHi<span class="token punctuation">(<span class="token punctuation">)<span class="token operator">: <span class="token builtin">string <span class="token punctuation">{
    <span class="token keyword">return <span class="token template-string"><span class="token template-punctuation string">`<span class="token string">My name is <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${<span class="token keyword">this<span class="token punctuation">.name<span class="token interpolation-punctuation punctuation">}<span class="token template-punctuation string">`<span class="token punctuation">;
<span class="token punctuation">}
<span class="token punctuation">}

<span class="token keyword">let a<span class="token operator">: Animal <span class="token operator">= <span class="token keyword">new <span class="token class-name">Animal<span class="token punctuation">(<span class="token string">'Jack'<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">(a<span class="token punctuation">.<span class="token function">sayHi<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// My name is Jack</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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>
<h1>六、类与接口</h1>
<p>之前学习过,接口(Interfaces)可以用于对「对象的形状(Shape)」进行描述。</p>
<p>这一章主要介绍接口的另一个用途,对类的一部分行为进行抽象。</p>
<h2 id="%E7%B1%BB%E5%AE%9E%E7%8E%B0%E6%8E%A5%E5%8F%A3">6.1、类实现接口<br></h2>
<p>实现(implements)是面向对象中的一个重要概念。一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用&nbsp;<code>implements</code>&nbsp;关键字来实现。这个特性大大提高了面向对象的灵活性。</p>
<p>举例来说,门是一个类,防盗门是门的子类。如果防盗门有一个报警器的功能,我们可以简单的给防盗门添加一个报警方法。这时候如果有另一个类,车,也有报警器的功能,就可以考虑把报警器提取出来,作为一个接口,防盗门和车都去实现它:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Alarm <span class="token punctuation">{
    <span class="token function">alert<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">class <span class="token class-name">Door <span class="token punctuation">{
<span class="token punctuation">}

<span class="token keyword">class <span class="token class-name">SecurityDoor <span class="token keyword">extends <span class="token class-name">Door <span class="token keyword">implements <span class="token class-name">Alarm <span class="token punctuation">{
    <span class="token function">alert<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">'SecurityDoor alert'<span class="token punctuation">)<span class="token punctuation">;
    <span class="token punctuation">}
<span class="token punctuation">}

<span class="token keyword">class <span class="token class-name">Car <span class="token keyword">implements <span class="token class-name">Alarm <span class="token punctuation">{
    <span class="token function">alert<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">'Car alert'<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></code></pre>
<p>一个类可以实现多个接口:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Alarm <span class="token punctuation">{
    <span class="token function">alert<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">Light <span class="token punctuation">{
    <span class="token function">lightOn<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">lightOff<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">class <span class="token class-name">Car <span class="token keyword">implements <span class="token class-name">Alarm<span class="token punctuation">, Light <span class="token punctuation">{
    <span class="token function">alert<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">'Car alert'<span class="token punctuation">)<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token function">lightOn<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">'Car light on'<span class="token punctuation">)<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token function">lightOff<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">'Car light off'<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></code></pre>
<p>上例中,<code>Car</code>&nbsp;实现了&nbsp;<code>Alarm</code>&nbsp;和&nbsp;<code>Light</code>&nbsp;接口,既能报警,也能开关车灯。</p>
<h2 id="%E6%8E%A5%E5%8F%A3%E7%BB%A7%E6%89%BF%E6%8E%A5%E5%8F%A3">6.2、接口继承接口<br></h2>
<p>接口与接口之间可以是继承关系:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Alarm <span class="token punctuation">{
    <span class="token function">alert<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">LightableAlarm <span class="token keyword">extends <span class="token class-name">Alarm <span class="token punctuation">{
    <span class="token function">lightOn<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">lightOff<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></span></span></span></span></span></span></span></span></span></code></pre>
<p>这很好理解,<code>LightableAlarm</code>&nbsp;继承了&nbsp;<code>Alarm</code>,除了拥有&nbsp;<code>alert</code>&nbsp;方法之外,还拥有两个新方法&nbsp;<code>lightOn</code>&nbsp;和&nbsp;<code>lightOff</code>。</p>
<h1>七、泛型</h1>
<p>泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。</p>
<h2 id="%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%8B%E5%AD%90">7.1、简单的例子<br></h2>
<p>首先,我们来实现一个函数&nbsp;<code>createArray</code>,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token function">createArray<span class="token punctuation">(length<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, value<span class="token operator">: <span class="token builtin">any<span class="token punctuation">)<span class="token operator">: <span class="token builtin">Array<span class="token operator">&lt;<span class="token builtin">any<span class="token operator">&gt; <span class="token punctuation">{
    <span class="token keyword">let result <span class="token operator">= <span class="token punctuation">[<span class="token punctuation">]<span class="token punctuation">;
    <span class="token keyword">for <span class="token punctuation">(<span class="token keyword">let i <span class="token operator">= <span class="token number">0<span class="token punctuation">; i <span class="token operator">&lt; length<span class="token punctuation">; i<span class="token operator">++<span class="token punctuation">) <span class="token punctuation">{
      result<span class="token punctuation"> <span class="token operator">= value<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return result<span class="token punctuation">;
<span class="token punctuation">}

<span class="token function">createArray<span class="token punctuation">(<span class="token number">3<span class="token punctuation">, <span class="token string">'x'<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// ['x', 'x', 'x']
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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>这段代码编译不会报错,但是一个显而易见的缺陷是,它并没有准确的定义返回值的类型:</p>
<p><code>Array&lt;any&gt;</code>&nbsp;允许数组的每一项都为任意类型。但是我们预期的是,数组中每一项都应该是输入的&nbsp;<code>value</code>&nbsp;的类型。</p>
<p>这时候,泛型就派上用场了:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token generic-function"><span class="token function">createArray<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">(length<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, value<span class="token operator">: <span class="token constant">T<span class="token punctuation">)<span class="token operator">: <span class="token builtin">Array<span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt; <span class="token punctuation">{
    <span class="token keyword">let result<span class="token operator">: <span class="token constant">T<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 keyword">for <span class="token punctuation">(<span class="token keyword">let i <span class="token operator">= <span class="token number">0<span class="token punctuation">; i <span class="token operator">&lt; length<span class="token punctuation">; i<span class="token operator">++<span class="token punctuation">) <span class="token punctuation">{
      result<span class="token punctuation"> <span class="token operator">= value<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return result<span class="token punctuation">;
<span class="token punctuation">}

<span class="token generic-function"><span class="token function">createArray<span class="token generic class-name"><span class="token operator">&lt;<span class="token builtin">string<span class="token operator">&gt;<span class="token punctuation">(<span class="token number">3<span class="token punctuation">, <span class="token string">'x'<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// ['x', 'x', 'x']
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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>&lt;T&gt;</code>,其中&nbsp;<code>T</code>&nbsp;用来指代任意输入的类型,在后面的输入&nbsp;<code>value: T</code>&nbsp;和输出&nbsp;<code>Array&lt;T&gt;</code>&nbsp;中即可使用了。</p>
<p>接着在调用的时候,可以指定它具体的类型为&nbsp;<code>string</code>。当然,也可以不手动指定,而让类型推论自动推算出来:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token generic-function"><span class="token function">createArray<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">(length<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, value<span class="token operator">: <span class="token constant">T<span class="token punctuation">)<span class="token operator">: <span class="token builtin">Array<span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt; <span class="token punctuation">{
    <span class="token keyword">let result<span class="token operator">: <span class="token constant">T<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 keyword">for <span class="token punctuation">(<span class="token keyword">let i <span class="token operator">= <span class="token number">0<span class="token punctuation">; i <span class="token operator">&lt; length<span class="token punctuation">; i<span class="token operator">++<span class="token punctuation">) <span class="token punctuation">{
      result<span class="token punctuation"> <span class="token operator">= value<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return result<span class="token punctuation">;
<span class="token punctuation">}

<span class="token function">createArray<span class="token punctuation">(<span class="token number">3<span class="token punctuation">, <span class="token string">'x'<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// ['x', 'x', 'x']
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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%A4%9A%E4%B8%AA%E7%B1%BB%E5%9E%8B%E5%8F%82%E6%95%B0">7.2、多个类型参数<br></h2>
<p>定义泛型的时候,可以一次定义多个类型参数:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token generic-function"><span class="token function">swap<span class="token generic class-name"><span class="token operator">&lt;<span class="token constant">T<span class="token punctuation">, <span class="token constant">U<span class="token operator">&gt;<span class="token punctuation">(tuple<span class="token operator">: <span class="token punctuation">[<span class="token constant">T<span class="token punctuation">, <span class="token constant">U<span class="token punctuation">]<span class="token punctuation">)<span class="token operator">: <span class="token punctuation">[<span class="token constant">U<span class="token punctuation">, <span class="token constant">T<span class="token punctuation">] <span class="token punctuation">{
    <span class="token keyword">return <span class="token punctuation"><span class="token punctuation">, tuple<span class="token punctuation">[<span class="token number">0<span class="token punctuation">]<span class="token punctuation">]<span class="token punctuation">;
<span class="token punctuation">}

<span class="token function">swap<span class="token punctuation">(<span class="token punctuation">[<span class="token number">7<span class="token punctuation">, <span class="token string">'seven'<span class="token punctuation">]<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// ['seven', 7]
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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>swap</code>&nbsp;函数,用来交换输入的元组。</p>
<h2 id="%E6%B3%9B%E5%9E%8B%E7%BA%A6%E6%9D%9F">7.3、泛型约束<br></h2>
<p>在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token generic-function"><span class="token function">loggingIdentity<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">(arg<span class="token operator">: <span class="token constant">T<span class="token punctuation">)<span class="token operator">: <span class="token constant">T <span class="token punctuation">{
    <span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(arg<span class="token punctuation">.length<span class="token punctuation">)<span class="token punctuation">;
    <span class="token keyword">return arg<span class="token punctuation">;
<span class="token punctuation">}

<span class="token comment">// index.ts(2,19): error TS2339: Property 'length' does not exist on type 'T'.
</span></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>T</code>&nbsp;不一定包含属性&nbsp;<code>length</code>,所以编译的时候报错了。</p>
<p>这时,我们可以对泛型进行约束,只允许这个函数传入那些包含&nbsp;<code>length</code>&nbsp;属性的变量。这就是泛型约束:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Lengthwise <span class="token punctuation">{
    length<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 generic-function"><span class="token function">loggingIdentity<span class="token generic class-name"><span class="token operator">&lt;<span class="token constant">T <span class="token keyword">extends Lengthwise<span class="token operator">&gt;<span class="token punctuation">(arg<span class="token operator">: <span class="token constant">T<span class="token punctuation">)<span class="token operator">: <span class="token constant">T <span class="token punctuation">{
    <span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(arg<span class="token punctuation">.length<span class="token punctuation">)<span class="token punctuation">;
    <span class="token keyword">return arg<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></code></pre>
<p>上例中,我们使用了&nbsp;<code>extends</code>&nbsp;约束了泛型&nbsp;<code>T</code>&nbsp;必须符合接口&nbsp;<code>Lengthwise</code>&nbsp;的形状,也就是必须包含&nbsp;<code>length</code>&nbsp;属性。</p>
<p>此时如果调用&nbsp;<code>loggingIdentity</code>&nbsp;的时候,传入的&nbsp;<code>arg</code>&nbsp;不包含&nbsp;<code>length</code>,那么在编译阶段就会报错了:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Lengthwise <span class="token punctuation">{
    length<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 generic-function"><span class="token function">loggingIdentity<span class="token generic class-name"><span class="token operator">&lt;<span class="token constant">T <span class="token keyword">extends Lengthwise<span class="token operator">&gt;<span class="token punctuation">(arg<span class="token operator">: <span class="token constant">T<span class="token punctuation">)<span class="token operator">: <span class="token constant">T <span class="token punctuation">{
    <span class="token builtin">console<span class="token punctuation">.<span class="token function">log<span class="token punctuation">(arg<span class="token punctuation">.length<span class="token punctuation">)<span class="token punctuation">;
    <span class="token keyword">return arg<span class="token punctuation">;
<span class="token punctuation">}

<span class="token function">loggingIdentity<span class="token punctuation">(<span class="token number">7<span class="token punctuation">)<span class="token punctuation">;

<span class="token comment">// index.ts(10,17): error TS2345: Argument of type '7' is not assignable to parameter of type 'Lengthwise'.
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></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">copyFields<span class="token generic class-name"><span class="token operator">&lt;<span class="token constant">T <span class="token keyword">extends <span class="token constant">U<span class="token punctuation">, <span class="token constant">U<span class="token operator">&gt;<span class="token punctuation">(target<span class="token operator">: <span class="token constant">T<span class="token punctuation">, source<span class="token operator">: <span class="token constant">U<span class="token punctuation">)<span class="token operator">: <span class="token constant">T <span class="token punctuation">{
    <span class="token keyword">for <span class="token punctuation">(<span class="token keyword">let id <span class="token keyword">in source<span class="token punctuation">) <span class="token punctuation">{
      target<span class="token punctuation"> <span class="token operator">= <span class="token punctuation">(<span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt;source<span class="token punctuation">)<span class="token punctuation"><span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return target<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let x <span class="token operator">= <span class="token punctuation">{ a<span class="token operator">: <span class="token number">1<span class="token punctuation">, b<span class="token operator">: <span class="token number">2<span class="token punctuation">, c<span class="token operator">: <span class="token number">3<span class="token punctuation">, d<span class="token operator">: <span class="token number">4 <span class="token punctuation">}<span class="token punctuation">;

<span class="token function">copyFields<span class="token punctuation">(x<span class="token punctuation">, <span class="token punctuation">{ b<span class="token operator">: <span class="token number">10<span class="token punctuation">, d<span class="token operator">: <span class="token number">20 <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></code></pre>
<p>上例中,我们使用了两个类型参数,其中要求&nbsp;<code>T</code>&nbsp;继承&nbsp;<code>U</code>,这样就保证了&nbsp;<code>U</code>&nbsp;上不会出现&nbsp;<code>T</code>&nbsp;中不存在的字段。</p>
<h2 id="%E6%B3%9B%E5%9E%8B%E6%8E%A5%E5%8F%A3">7.4、泛型接口<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>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">CreateArrayFunc <span class="token punctuation">{
    <span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt;<span class="token punctuation">(length<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, value<span class="token operator">: <span class="token constant">T<span class="token punctuation">)<span class="token operator">: <span class="token builtin">Array<span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt;<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let createArray<span class="token operator">: CreateArrayFunc<span class="token punctuation">;
<span class="token function-variable function">createArray <span class="token operator">= <span class="token keyword">function<span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt;<span class="token punctuation">(length<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, value<span class="token operator">: <span class="token constant">T<span class="token punctuation">)<span class="token operator">: <span class="token builtin">Array<span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt; <span class="token punctuation">{
    <span class="token keyword">let result<span class="token operator">: <span class="token constant">T<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 keyword">for <span class="token punctuation">(<span class="token keyword">let i <span class="token operator">= <span class="token number">0<span class="token punctuation">; i <span class="token operator">&lt; length<span class="token punctuation">; i<span class="token operator">++<span class="token punctuation">) <span class="token punctuation">{
      result<span class="token punctuation"> <span class="token operator">= value<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return result<span class="token punctuation">;
<span class="token punctuation">}

<span class="token function">createArray<span class="token punctuation">(<span class="token number">3<span class="token punctuation">, <span class="token string">'x'<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// ['x', 'x', 'x']
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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">CreateArrayFunc<span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt; <span class="token punctuation">{
    <span class="token punctuation">(length<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, value<span class="token operator">: <span class="token constant">T<span class="token punctuation">)<span class="token operator">: <span class="token builtin">Array<span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt;<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let createArray<span class="token operator">: CreateArrayFunc<span class="token operator">&lt;<span class="token builtin">any<span class="token operator">&gt;<span class="token punctuation">;
<span class="token function-variable function">createArray <span class="token operator">= <span class="token keyword">function<span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt;<span class="token punctuation">(length<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, value<span class="token operator">: <span class="token constant">T<span class="token punctuation">)<span class="token operator">: <span class="token builtin">Array<span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt; <span class="token punctuation">{
    <span class="token keyword">let result<span class="token operator">: <span class="token constant">T<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 keyword">for <span class="token punctuation">(<span class="token keyword">let i <span class="token operator">= <span class="token number">0<span class="token punctuation">; i <span class="token operator">&lt; length<span class="token punctuation">; i<span class="token operator">++<span class="token punctuation">) <span class="token punctuation">{
      result<span class="token punctuation"> <span class="token operator">= value<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return result<span class="token punctuation">;
<span class="token punctuation">}

<span class="token function">createArray<span class="token punctuation">(<span class="token number">3<span class="token punctuation">, <span class="token string">'x'<span class="token punctuation">)<span class="token punctuation">; <span class="token comment">// ['x', 'x', 'x']
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></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>
<h2 id="%E6%B3%9B%E5%9E%8B%E7%B1%BB">7.5、泛型类<br></h2>
<p>与泛型接口类似,泛型也可以用于类的类型定义中:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">class <span class="token class-name">GenericNumber<span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt; <span class="token punctuation">{
    zeroValue<span class="token operator">: <span class="token constant">T<span class="token punctuation">;
    <span class="token function-variable function">add<span class="token operator">: <span class="token punctuation">(x<span class="token operator">: <span class="token constant">T<span class="token punctuation">, y<span class="token operator">: <span class="token constant">T<span class="token punctuation">) <span class="token operator">=&gt; <span class="token constant">T<span class="token punctuation">;
<span class="token punctuation">}

<span class="token keyword">let myGenericNumber <span class="token operator">= <span class="token keyword">new <span class="token class-name">GenericNumber<span class="token operator">&lt;<span class="token builtin">number<span class="token operator">&gt;<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">;
myGenericNumber<span class="token punctuation">.zeroValue <span class="token operator">= <span class="token number">0<span class="token punctuation">;
myGenericNumber<span class="token punctuation">.<span class="token function-variable function">add <span class="token operator">= <span class="token keyword">function<span class="token punctuation">(x<span class="token punctuation">, y<span class="token punctuation">) <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></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<h2 id="%E6%B3%9B%E5%9E%8B%E5%8F%82%E6%95%B0%E7%9A%84%E9%BB%98%E8%AE%A4%E7%B1%BB%E5%9E%8B">7.6、泛型参数的默认类型<br></h2>
<p>在 TypeScript 2.3 以后,我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用。</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function <span class="token generic-function"><span class="token function">createArray<span class="token generic class-name"><span class="token operator">&lt;<span class="token constant">T <span class="token operator">= <span class="token builtin">string<span class="token operator">&gt;<span class="token punctuation">(length<span class="token operator">: <span class="token builtin">number<span class="token punctuation">, value<span class="token operator">: <span class="token constant">T<span class="token punctuation">)<span class="token operator">: <span class="token builtin">Array<span class="token operator">&lt;<span class="token constant">T<span class="token operator">&gt; <span class="token punctuation">{
    <span class="token keyword">let result<span class="token operator">: <span class="token constant">T<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 keyword">for <span class="token punctuation">(<span class="token keyword">let i <span class="token operator">= <span class="token number">0<span class="token punctuation">; i <span class="token operator">&lt; length<span class="token punctuation">; i<span class="token operator">++<span class="token punctuation">) <span class="token punctuation">{
      result<span class="token punctuation"> <span class="token operator">= value<span class="token punctuation">;
    <span class="token punctuation">}
    <span class="token keyword">return result<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></code></pre>
<h1>八、声明合并</h1>
<p>如果定义了两个相同名字的函数、接口或类,那么它们会合并成一个类型:</p>
<h2 id="%E5%87%BD%E6%95%B0%E7%9A%84%E5%90%88%E5%B9%B6">8.1、函数的合并<br></h2>
<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 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 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></code></pre>
<h2 id="%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%90%88%E5%B9%B6">8.2、接口的合并<br></h2>
<p>接口中的属性在合并时会简单的合并到一个接口中:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Alarm <span class="token punctuation">{
    price<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">Alarm <span class="token punctuation">{
    weight<span class="token operator">: <span class="token builtin">number<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">interface <span class="token class-name">Alarm <span class="token punctuation">{
    price<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    weight<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}
</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">Alarm <span class="token punctuation">{
    price<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">Alarm <span class="token punctuation">{
    price<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;<span class="token comment">// 虽然重复了,但是类型都是 `number`,所以不会报错
    weight<span class="token operator">: <span class="token builtin">number<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>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Alarm <span class="token punctuation">{
    price<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">Alarm <span class="token punctuation">{
    price<span class="token operator">: <span class="token builtin">string<span class="token punctuation">;<span class="token comment">// 类型不一致,会报错
    weight<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
<span class="token punctuation">}

<span class="token comment">// index.ts(5,3): error TS2403: Subsequent variable declarations must have the same type.Variable 'price' must be of type 'number', but here has type 'string'.
</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">Alarm <span class="token punctuation">{
    price<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    <span class="token function">alert<span class="token punctuation">(s<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 punctuation">}
<span class="token keyword">interface <span class="token class-name">Alarm <span class="token punctuation">{
    weight<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    <span class="token function">alert<span class="token punctuation">(s<span class="token operator">: <span class="token builtin">string<span class="token punctuation">, n<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 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></code></pre>
<p>相当于:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">interface <span class="token class-name">Alarm <span class="token punctuation">{
    price<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    weight<span class="token operator">: <span class="token builtin">number<span class="token punctuation">;
    <span class="token function">alert<span class="token punctuation">(s<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 function">alert<span class="token punctuation">(s<span class="token operator">: <span class="token builtin">string<span class="token punctuation">, n<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 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>
<h2 id="%E7%B1%BB%E7%9A%84%E5%90%88%E5%B9%B6">8.3、类的合并<br></h2>
<p>类的合并与接口的合并规则一致。</p><br><br>
来源:https://www.cnblogs.com/best/p/16472778.html
頁: [1]
查看完整版本: TypeScript学习笔记(四)—— TypeScript提高