腾讯老衲衲 發表於 2020-12-10 12:27:00

TypeScript:入门TS

<h2 id="0">什么是 TypeScript</h2>
<p>官方网站的定义是:<strong>TypeScript 是&nbsp;js&nbsp;类型的超集</strong>。它假设咱们知道什么是超集,什么是类型化。为了简单起见,你可以将&nbsp;<strong>TypeScript 看作是&nbsp;JavaScript&nbsp;之上的一个外壳</strong>。</p>
<p>TypeScript&nbsp;是一个外壳,因为编写 TypeScript 的代码,在编译之后,,剩下的只是简单的&nbsp;js&nbsp;代码。</p>
<p>但是 JS 引擎无法读取 TypeScript 代码,因此任何 TypeScript 文件都应该经过<strong>预翻译</strong>过程,即<strong>编译</strong>。只有在第一个编译步骤之后,才剩下纯 JS 代码,可以在浏览器中运行。稍后会介绍 TypeScript 编译是如何完成的。</p>
<p>现在让我们记住 TypeScript 是一种特殊的 JS,在浏览器中运行之前它需要一个翻译。</p>
<p>&nbsp;</p>
<h2 id="1">为什么要使用 TypeScript</h2>
<p>刚开始,咱们不完全理解 TypeScript 为何有意义。 你可能会问“ TypeScript 的目的是什么”。 这是一个很好的问题。</p>
<p>实际上,一旦它在您的代码中发现严重和愚蠢的错误,你就会看到 TypeScript 的好处。更重要的是,TypeScript 会让代码变得结构良好而且还是自动,这些还只是 TypeScript 的一小部分。</p>
<p>不管怎样,也经常有人说 TypeScript 没用,太过笨拙。</p>
<p>凡事都有两面性,TypeScript 有很多反对者和支持者,但重要的是 TypeScript 是一个可靠的工具,将它放在咱们的工具技能包中不会造成伤害。</p>
<p>&nbsp;</p>
<h2 id="2">TypeScript 配置</h2>
<p>为什么配置? TypeScript 还有一个二进制文件,可将 TypeScript 代码编译为 JS 代码. 请记住,浏览器不理解 TypeScript:</p>
<pre><code class="hljs nginx"><span class="hljs-attribute">mkdir typescript-tutorial &amp;&amp; cd <span class="hljs-variable">$_
npm init -y
</span></span></code></pre>
<p>然后安装 TypeScript</p>
<pre><code class="hljs nginx">npm i typescript --save-dev
</code></pre>
<p>接下来在&nbsp;package.json&nbsp;中的&nbsp;scripts&nbsp;下添加如下内容,以便咱们可以轻松地运行 TypeScript 编译器:</p>
<pre><code class="hljs php"><span class="hljs-string">"scripts": {
    <span class="hljs-string">"tsc": <span class="hljs-string">"tsc"
}
</span></span></span></code></pre>
<p><strong>tsc 代表 TypeScript 编译器</strong>,只要编译器运行,它将在项目文件夹中查找名为<strong>tsconfig.json</strong>&nbsp;的文件。 使用以下命令为 TypeScript 生成配置文件:</p>
<pre><code class="hljs nginx"><span class="hljs-attribute">npm run tsc -- --init
</span></code></pre>
<p>执行成功后会在控制台收到&nbsp;message TS6071: Successfully created a tsconfig.json file。在项目文件夹中会看到新增了一个&nbsp;tsconfig.json&nbsp;文件。tsconfig。json&nbsp;是一个可怕的配置文件,不要慌。咱们不需要知道它的每一个要点,在下一节中,会介绍入门的相关部分。</p>
<p>&nbsp;</p>
<h2 id="3">配置TypeScript 编译器</h2>
<p>最好先初始化 git repo 并提交原始的&nbsp;<strong>tsconfig.json</strong>,然后再打开文件。 我们将只保留一些配置选项,并删除其他所有内容。 稍后,你可能需要将现在的版本与原始版本进行比较。</p>
<p>首先,请打开&nbsp;tsconfig.json&nbsp;并将所有原始内容替换为以下内容:</p>
<pre><code class="hljs json">{
<span class="hljs-attr">"compilerOptions": {
    <span class="hljs-attr">"target": <span class="hljs-string">"es5",
    <span class="hljs-attr">"strict": <span class="hljs-literal">true
}
}
</span></span></span></span></span></code></pre>
<p>保存并关闭文件。 首先,你可能想知道&nbsp;<strong>tsconfig.json</strong>&nbsp;是干什么的。 该配置文件由 TypeScript 编译器和任何具有 TypeScript 支持的代码编辑器读取。</p>
<ul>
<li><strong>noImplicitAny</strong>&nbsp;true:当变量没有定义类型时,TypeScript 会报错</li>
<li><strong>alwaysStrict</strong>&nbsp;true:严格模式是 JS 的安全机制,它可以防止意外的全局变量,默认的&nbsp;this&nbsp;绑定等。 设置为 “alwaysStrict” 时,TypeScript 在每个KS 文件的顶部都使用&nbsp;“use strict”&nbsp;。</li>
</ul>
<p>有更多的配置选项可用。随着时间的推移,你会学到更多,因为现在上面的两个选择是你开始学习时需要知道的一切。</p>
<p>&nbsp;</p>
<h2 id="4">关于类型的几个词</h2>
<p>TypeScript 支持与 JS 几乎相同的数据类型,此外,TypeScript 自己添加了更多的类型,如&nbsp;any&nbsp;类型一样。</p>
<p>“any”&nbsp;是松散的 TypeScript 类型。 这意味着:此变量可以是任何类型:字符串,布尔值,对象等。 实际上,这就像根本没有类型检查。</p>
<p>&nbsp;</p>
<h2 id="5">TypeScript 中的行为</h2>
<p>咱们从一个合法的 KS函数开始:<strong>filterByTerm</strong>。在项目文件夹中创建一个名为&nbsp;<strong>filterByTerm.js</strong>&nbsp;的新文件,并输入以下内容</p>
<pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm(<span class="hljs-params">input, searchTerm) {
<span class="hljs-keyword">if (!searchTerm) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"searchTerm 不能为空");
<span class="hljs-keyword">if (!input.length) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"input 不能为空");
<span class="hljs-keyword">const</span> regex = <span class="hljs-keyword">new <span class="hljs-built_in">RegExp(searchTerm, <span class="hljs-string">"i");
<span class="hljs-keyword">return input.filter(<span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">arrayElement) {
    <span class="hljs-keyword">return arrayElement.url.match(regex);
});
}

filterByTerm(<span class="hljs-string">"input string", <span class="hljs-string">"java");
</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>我想知道是否有一种方法可以在我的 IDE 中检查这个函数,而不需要运行代码或者用Jest测试它。这可能吗? TypeScript 在这方面做得很好,实际上它是 JS 中静态检查的最佳工具,也就是说,<strong>在代码运行之前测试代码的正确性</strong>。</p>
<p>因此,咱们改用 TypeScript ,将文件的扩展名从&nbsp;<strong>filterByTerm.js</strong>&nbsp;改为&nbsp;<strong>filterByTerm.ts</strong>。通过这种更改,你会发现代码中的一堆错误</p>
<p><img src="http://api.fly63.com/vue_blog/public/Uploads/20191105/5dc17c116f615.jpg"></p>
<p>可以看到函数参数下的有很多红色标记。从现在开始,会向你展示文本形式的错误,但是请记住,当咱们在TypeScript 中出错时,IDE 和文本编辑器都会显示这些红线。</p>
<p>确定哪个地方错:</p>
<pre><code class="hljs nginx"><span class="hljs-attribute">npm run tsc
</span></code></pre>
<p>可以看到控制的报错:</p>
<pre><code class="hljs php">filterByTerm.ts:<span class="hljs-number">1:<span class="hljs-number">23 - error TS7006: Parameter <span class="hljs-string">'input' implicitly has an <span class="hljs-string">'any' type.

<span class="hljs-number">1 <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm<span class="hljs-params">(input, searchTerm) {
                        ~~~~~

filterByTerm.ts:<span class="hljs-number">1:<span class="hljs-number">30 - error TS7006: Parameter <span class="hljs-string">'searchTerm' implicitly has an <span class="hljs-string">'any' type.

<span class="hljs-number">1 <span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm<span class="hljs-params">(input, searchTerm) {
                               ~~~~~~~~~~

filterByTerm.ts:<span class="hljs-number">5:<span class="hljs-number">32 - error TS7006: Parameter <span class="hljs-string">'arrayElement' implicitly has an <span class="hljs-string">'any' type.

<span class="hljs-number">5   <span class="hljs-keyword">return input.filter(<span class="hljs-function"><span class="hljs-keyword">function<span class="hljs-params">(arrayElement) {
</span></span></span></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;“any”&nbsp;类型,如果还记得的话,它可以是 TypeScript 中的&nbsp;any&nbsp;类型。 我们需要在我们的 TypeScript 代码中添加适当的类型注释。</p>
<p>&nbsp;</p>
<h2 id="6">什么是类型,JS 中有什么问题</h2>
<p>到目前为止,JS 有七种类型</p>
<ul>
<li>String</li>
<li>Number</li>
<li>Boolean</li>
<li>Null</li>
<li>Undefined</li>
<li>Object</li>
<li>Symbol (ES6)</li>
</ul>
<p>除了 Object 类型外,其它是 JS 的基本数据类型。每种 JS 类型都有相应的表示,可以代码中使用,比如字符串和数字</p>
<pre><code class="hljs php"><span class="hljs-keyword">var</span> name = <span class="hljs-string">"Hello John";
<span class="hljs-keyword">var</span> age = <span class="hljs-number">33;
</span></span></code></pre>
<p>JS 的问题是,变量可以随时更改其类型。例如,布尔值可以变成字符串(将以下代码保存到名为&nbsp;<strong>types.js</strong>&nbsp;的文件中)</p>
<pre><code class="hljs javascript"><span class="hljs-keyword">var aBoolean = <span class="hljs-literal">false;
<span class="hljs-built_in">console.log(<span class="hljs-keyword">typeof aBoolean); <span class="hljs-comment">// "boolean"

aBoolean = <span class="hljs-string">"Tom";
<span class="hljs-built_in">console.log(<span class="hljs-keyword">typeof aBoolean); <span class="hljs-comment">// "string"
</span></span></span></span></span></span></span></span></span></code></pre>
<p>转换可以是有意的,开发人员可能真的希望将&nbsp;Tom&nbsp;分配到&nbsp;aBoolean,但是这类错误很可能是偶然发生的。</p>
<p>从技术上讲,JS 本身没有什么问题,因为它的类型动态是故意的。JS 是作为一种简单的 web 脚本语言而诞生的,而不是作为一种成熟的企业语言。</p>
<p>然而,JS 松散的特性可能会在你的代码中造成严重的问题,破坏其可维护性。TypeScript 旨在通过向 JS 添加强类型来解决这些问题。实际上,如果将&nbsp;<strong>types.js</strong>&nbsp;的扩展更改为&nbsp;<strong>types.ts</strong>&nbsp;。你会在IDE中看到 TypeScript 的抱怨。</p>
<p>types.ts&nbsp;的编译控制台会报错:</p>
<pre><code class="hljs php">types.ts:<span class="hljs-number">4:<span class="hljs-number">1 - error TS2322: Type <span class="hljs-string">'"Tom"' is not assignable to type <span class="hljs-string">'boolean'.
</span></span></span></span></code></pre>
<p>有了这些知识,接着,咱们更深入地研究 TypeScript 类型。</p>
<p>&nbsp;</p>
<h2 id="7">深入 TypeScript 类型</h2>
<p>TypeScript 强调有类型,咱们上面的代码根本没有类型,是时候添加一些了。首先要修正函数参数。通过观察这个函数是如何调用的,它似乎以两个字符串作为参数:</p>
<pre><code class="hljs php">filterByTerm(<span class="hljs-string">"input string", <span class="hljs-string">"java");
</span></span></code></pre>
<p>为参数添加类型:</p>
<pre><code class="hljs php"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm<span class="hljs-params">(input: string, searchTerm: string) {
    <span class="hljs-comment">// ...
}

<span class="hljs-comment">// ...
</span></span></span></span></span></span></code></pre>
<p>接着编译:</p>
<pre><code class="hljs nginx"><span class="hljs-attribute">npm run tsc
</span></code></pre>
<p>剩下的错误:</p>
<pre><code class="hljs php">filterByTerm.ts:<span class="hljs-number">5:<span class="hljs-number">16 - error TS2339: Property <span class="hljs-string">'filter' does not exist on type <span class="hljs-string">'string'.
</span></span></span></span></code></pre>
<p>可以看到 TypeScript 是如何指导我们,现在的问题在于&nbsp;filter&nbsp;方法。</p>
<pre><code class="hljs php"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm<span class="hljs-params">(input: string, searchTerm: string) {
<span class="hljs-comment">// 省略一些
<span class="hljs-keyword">return input.filter(<span class="hljs-function"><span class="hljs-keyword">function<span class="hljs-params">(arrayElement) {
    <span class="hljs-keyword">return arrayElement.url.match(regex);
});
}
</span></span></span></span></span></span></span></span></span></span></code></pre>
<p>咱们告诉 TypeScript&nbsp;“input”&nbsp;是一个字符串,但是在后面的代码中调用了&nbsp;filter&nbsp;方法,它属于数组。我们真正需要的是将输入标记为某个东西的数组,可能是字符串数组:</p>
<p>为此,有两个选择。选项1:string[]</p>
<pre><code class="hljs php"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm<span class="hljs-params">(input: string[], searchTerm: string) {
    <span class="hljs-comment">// ...
}
</span></span></span></span></span></code></pre>
<p>选项2:&nbsp;Array&lt;Type&gt;</p>
<pre><code class="hljs php"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm<span class="hljs-params">(input: Array&lt;string&gt;, searchTerm: string) {
    <span class="hljs-comment">// ...

}
</span></span></span></span></span></code></pre>
<p>我个人更喜欢选项2。 现在,尝试再次编译(npm run tsc),控制台信息如下:</p>
<pre><code class="hljs javascript">filterByTerm.ts:<span class="hljs-number">10:<span class="hljs-number">14 - error TS2345: Argument <span class="hljs-keyword">of type <span class="hljs-string">'"input string"' is not assignable to parameter <span class="hljs-keyword">of type <span class="hljs-string">'string[]'.

filterByTerm(<span class="hljs-string">"input string", <span class="hljs-string">"java");

</span></span></span></span></span></span></span></span></code></pre>
<p>TypeScript 还会校验传入的类型。 我们将&nbsp;input&nbsp;改为字符串数组:</p>
<pre><code class="hljs php">filterByTerm([<span class="hljs-string">"string1", <span class="hljs-string">"string2", <span class="hljs-string">"string3"], <span class="hljs-string">"java");
</span></span></span></span></code></pre>
<p>这是到目前为止的完整代码:</p>
<pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm(<span class="hljs-params">input: Array&lt;string&gt;, searchTerm: string) {
<span class="hljs-keyword">if (!searchTerm) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"searchTerm 不能为空");
<span class="hljs-keyword">if (!input.length) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"input 不能为空");
<span class="hljs-keyword">const</span> regex = <span class="hljs-keyword">new <span class="hljs-built_in">RegExp(searchTerm, <span class="hljs-string">"i");
<span class="hljs-keyword">return input.filter(<span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">arrayElement) {
    <span class="hljs-keyword">return arrayElement.url.match(regex);
});
}

filterByTerm([<span class="hljs-string">"string1", <span class="hljs-string">"string2", <span class="hljs-string">"string3"], <span class="hljs-string">"java");
</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>看上去很好,但是,编译(npm run tsc)还是过不了:</p>
<pre><code class="hljs php">filterByTerm.ts:<span class="hljs-number">6:<span class="hljs-number">25 - error TS2339: Property <span class="hljs-string">'url' does not exist on type <span class="hljs-string">'string'.
</span></span></span></span></code></pre>
<p>TypeScript 确实很严谨。 我们传入了一个字符串数组,但是在代码后面,尝试访问一个名为&nbsp;“url”&nbsp;的属性:</p>
<pre><code class="hljs css"><span class="hljs-selector-tag">return <span class="hljs-selector-tag">arrayElement<span class="hljs-selector-class">.url<span class="hljs-selector-class">.match(<span class="hljs-selector-tag">regex);
</span></span></span></span></span></code></pre>
<p>这意味着咱们需要一个对象数组,而不是字符串数组。咱们在下一节中解决这个问题。</p>
<p>&nbsp;</p>
<h2 id="8">TypeScript 对象和接口</h2>
<p>上面遗留一个问题:因为&nbsp;filterByTerm&nbsp;被传递了一个字符串数组。url&nbsp;属性在类型为&nbsp;string&nbsp;的TypeScript 上不存在。所以咱们改用传递一个对象数组来解决这个问题:</p>
<pre><code class="hljs php">filterByTerm(
[{ url: <span class="hljs-string">"string1" }, { url: <span class="hljs-string">"string2" }, { url: <span class="hljs-string">"string3" }],
<span class="hljs-string">"java"
);
</span></span></span></span></code></pre>
<p>函数定义也要对应的更改:</p>
<pre><code class="hljs php"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm<span class="hljs-params">(input: Array&lt;object&gt;, searchTerm: string) {
    <span class="hljs-comment">// omitted
}

</span></span></span></span></span></code></pre>
<p>现在让我们编译代码</p>
<pre><code class="hljs nginx"><span class="hljs-attribute">npm run tsc
</span></code></pre>
<p>控制输出:</p>
<pre><code class="hljs php">filterByTerm.ts:<span class="hljs-number">6:<span class="hljs-number">25 - error TS2339: Property <span class="hljs-string">'url' does not exist on type <span class="hljs-string">'object'.
</span></span></span></span></code></pre>
<p>又来了,通用 JS 对象没有任何名为&nbsp;url&nbsp;的属性。对我来说,TypeScript 对类型要求真的是很严谨。</p>
<p>这里的问题是,咱们不能给一个随机对象分配属性,TypeScript 的核心原则之一是对值所具有的结构进行类型检查, 在 TypeScript 里,<strong>接口(interface)</strong>的作用就是为这些类型命名和为你的代码或第三方代码定义契约,咱们可以使用<strong>接口</strong>来解决这个问题。</p>
<p>通过查看我们的代码,我们可以想到一个名为&nbsp;Link&nbsp;的简单<strong>"模型"</strong>,其结构应该符合以下模式:它必须有一个类型为&nbsp;string&nbsp;的&nbsp;url&nbsp;属性。</p>
<p>在TypeScript 中,你可以用一个接口来定义这个模型,就像这样(把下面的代码放在&nbsp;<strong>filterByTerm.ts</strong>&nbsp;的顶部):</p>
<pre><code class="hljs css"><span class="hljs-selector-tag">interface <span class="hljs-selector-tag">ILink {
<span class="hljs-attribute">url: string;
}
</span></span></span></code></pre>
<p>对于接口声明,这当然不是有效的 JS&nbsp;语法,在编译过程中会被删除。</p>
<p><strong>提示</strong>:在定义接口名字前面加上大写的I,这是 TypeScript 的惯例。</p>
<p>现在,使用使用接口&nbsp;ILink&nbsp;定义&nbsp;input&nbsp;类型</p>
<pre><code class="hljs php"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm<span class="hljs-params">(input: Array&lt;ILink&gt;, searchTerm: string) {
    <span class="hljs-comment">// ...
}
</span></span></span></span></span></code></pre>
<p>通过此修复,可以说 TypeScript “期望&nbsp;<strong>ILink</strong>&nbsp;数组”作为该函数的输入,以下是完整的代码:</p>
<pre><code class="hljs javascript">interface ILink {
<span class="hljs-attr">url: string;
}

<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm(<span class="hljs-params">input: Array&lt;ILink&gt;, searchTerm: string) {
<span class="hljs-keyword">if (!searchTerm) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"searchTerm 不能为空");
<span class="hljs-keyword">if (!input.length) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"input 不能为空");
<span class="hljs-keyword">const regex = <span class="hljs-keyword">new <span class="hljs-built_in">RegExp(searchTerm, <span class="hljs-string">"i");
<span class="hljs-keyword">return input.filter(<span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">arrayElement) {
    <span class="hljs-keyword">return arrayElement.url.match(regex);
});
}

filterByTerm(
[{ <span class="hljs-attr">url: <span class="hljs-string">"string1" }, { <span class="hljs-attr">url: <span class="hljs-string">"string2" }, { <span class="hljs-attr">url: <span class="hljs-string">"string3" }],
<span class="hljs-string">"java"
);
</span></span></span></span></span></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><code class="hljs nginx"><span class="hljs-attribute">npm run tsc
</span></code></pre>
<p>编译后,会在项目文件夹中生成一个名为&nbsp;<strong>filterByTerm.js</strong>&nbsp;的文件,其中包含纯 JS 代码。可以检出该文件并查看 TypeScript 特定的声明最终转换成 JS 的是什么样的。</p>
<p>因为&nbsp;alwaysStrict&nbsp;设置为&nbsp;true,所以 TypeScript 编译器也会在&nbsp;<strong>filterByTerm.js</strong>&nbsp;的顶部使用&nbsp;use strict。</p>
<p>&nbsp;</p>
<h2 id="9">接口和字段</h2>
<p>TypeScript 接口是该语言最强大的结构之一。接口有助于在整个应用程序中形成模型,这样任何开发人员在编写代码时都可以选择这种模型并遵循它。</p>
<p>前面,咱们定义了一个简单的接口&nbsp;ILink</p>
<pre><code class="hljs css"><span class="hljs-selector-tag">interface <span class="hljs-selector-tag">ILink {
<span class="hljs-attribute">url: string;
}
</span></span></span></code></pre>
<p>如果您想要向接口添加更多的字段,只需在块中声明它们即可:</p>
<pre><code class="hljs css"><span class="hljs-selector-tag">interface <span class="hljs-selector-tag">ILink {
<span class="hljs-attribute">description: string;
<span class="hljs-attribute">id: number;
<span class="hljs-attribute">url: string;
}
</span></span></span></span></span></code></pre>
<p>现在,类型为ILink的对象都必须实现新字段,否则就会出现错误,如果把上面 的定义重新写入&nbsp;<strong>filterByTerm.ts</strong>&nbsp;然后重新编译就会报错了:</p>
<pre><code class="hljs javascript">filterByTerm.ts:<span class="hljs-number">17:<span class="hljs-number">4 - error TS2739: Type <span class="hljs-string">'{ url: string; }' is missing the following properties <span class="hljs-keyword">from type <span class="hljs-string">'ILink': description, id
</span></span></span></span></span></code></pre>
<p>问题在于我们函数的参数:</p>
<pre><code class="hljs php">filterByTerm(
[{ url: <span class="hljs-string">"string1" }, { url: <span class="hljs-string">"string2" }, { url: <span class="hljs-string">"string3" }],
<span class="hljs-string">"java"
);
</span></span></span></span></code></pre>
<p>TypeScript 可以通过函数声明来推断参数是&nbsp;ILink&nbsp;的类型数组。因此,该数组中的任何对象都必须实现接口&nbsp;<strong>ILink</strong>&nbsp;中定义的所有字段</p>
<p>大多数情况下,实现所有字段是不太现实的。毕竟,咱也不知道&nbsp;ILink&nbsp;类型的每个新对象是否会需要拥有所有字段。不过不要担心,要使编译通过,可以声明接口的字段<strong>可选</strong>,使用&nbsp;?&nbsp;表示:</p>
<pre><code class="hljs php"><span class="hljs-class"><span class="hljs-keyword">interface <span class="hljs-title">ILink {
description?: string;
id?: number;
url: string;
}
</span></span></span></code></pre>
<p>现在编辑器和编译器都没问题了。然而 TypeScript 接口可以做的更多,在下一节我们将看到如何扩展它们。但首先简要介绍一下 TypeScript 中的变量。</p>
<p>&nbsp;</p>
<h2 id="10">变量声明</h2>
<p>到目前为止,咱们已经了解了如何向函数参数中添加类型:</p>
<pre><code class="hljs php"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm<span class="hljs-params">(input: Array&lt;ILink&gt;, searchTerm: string) {
    <span class="hljs-comment">//
}

</span></span></span></span></span></code></pre>
<p>TypeScript 并不限于此,当然也可以向任何变量添加类型。为了说明这个例子,咱们一一地提取函数的参数。首先咱要提取每一个单独的对象:</p>
<pre><code class="hljs php"><span class="hljs-keyword">const obj1: ILink = { url: <span class="hljs-string">"string1" };
<span class="hljs-keyword">const obj2: ILink = { url: <span class="hljs-string">"string2" };
<span class="hljs-keyword">const obj3: ILink = { url: <span class="hljs-string">"string3" };
</span></span></span></span></span></span></code></pre>
<p>接下来我们可以像这样定义一个&nbsp;ILink&nbsp;数组:</p>
<pre><code class="hljs php"><span class="hljs-keyword">const arrOfLinks: <span class="hljs-keyword">Array&lt;ILink&gt; = ;
</span></span></code></pre>
<p>参数&nbsp;searchTerm&nbsp;对应的类型可以这样:</p>
<pre><code class="hljs php"><span class="hljs-keyword">const term: string = <span class="hljs-string">"java";
</span></span></code></pre>
<p>以下是完整的代码:</p>
<pre><code class="hljs javascript">interface ILink {
description?: string;
id?: number;
url: string;
}

<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm(<span class="hljs-params">input: Array&lt;ILink&gt;, searchTerm: string) {
<span class="hljs-keyword">if (!searchTerm) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"searchTerm 不能为空");
<span class="hljs-keyword">if (!input.length) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"input 不能为空");
<span class="hljs-keyword">const regex = <span class="hljs-keyword">new <span class="hljs-built_in">RegExp(searchTerm, <span class="hljs-string">"i");
<span class="hljs-keyword">return input.filter(<span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">arrayElement) {
    <span class="hljs-keyword">return arrayElement.url.match(regex);
});
}

<span class="hljs-keyword">const obj1: ILink = { <span class="hljs-attr">url: <span class="hljs-string">"string1" };
<span class="hljs-keyword">const obj2: ILink = { <span class="hljs-attr">url: <span class="hljs-string">"string2" };
<span class="hljs-keyword">const obj3: ILink = { <span class="hljs-attr">url: <span class="hljs-string">"string3" };

<span class="hljs-keyword">const arrOfLinks: <span class="hljs-built_in">Array&lt;ILink&gt; = ;

<span class="hljs-keyword">const term: string = <span class="hljs-string">"java";

filterByTerm(arrOfLinks, term);
</span></span></span></span></span></span></span></span></span></span></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>与 JS 相比,TypeScript看起来更冗长,有时甚至是多余的。但是随着时间的推移,会发现添加的类型越多,代码就越健壮。</p>
<p>通过添加类型注释,对 TypeScript 的了解也越多,还可以帮助你更好地理解代码的意图。</p>
<p>例如,arrOfLinks&nbsp;与正确的类型(ILink的数组)相关联,咱们编辑器就可以推断出数组中的每个对象都有一个名为url的属性,如接口&nbsp;ILink&nbsp;中所定义:</p>
<p><img src="http://api.fly63.com/vue_blog/public/Uploads/20191105/5dc17c2c1c263.jpg"></p>
<p>除了字符串、数组和数字之外,TypeScript 还有更多类型。有&nbsp;boolean,<strong>tuple (元组)</strong>,<strong>any</strong>,&nbsp;<strong>never</strong>,enum&nbsp;。如果你感兴趣,可以查看文档。</p>
<p>现在,咱们继续扩展接口。</p>
<p>&nbsp;</p>
<h2 id="11">扩展接口</h2>
<p>TypeScript 接口很好。但是,如果哪天咱们需要一个新的对象,所需的类型跟现在有接口基本差不多。假设我们需要一个名为&nbsp;IPost&nbsp;的新接口,它具有以下属性:</p>
<ul>
<li>id, number</li>
<li>title, string</li>
<li>body, string</li>
<li>url, string</li>
<li>description, string</li>
</ul>
<p>该接口的字段其中有些,我们&nbsp;ILink&nbsp;接口都有了。</p>
<pre><code class="hljs php"><span class="hljs-class"><span class="hljs-keyword">interface <span class="hljs-title">ILink {
description?: string;
id?: number;
url: string;
}
</span></span></span></code></pre>
<p>是否有办法重用接口&nbsp;<strong>ILink</strong>&nbsp;? 在 TypeScript 中,可以使用继承来扩展接口,关键字用&nbsp;<strong>extends</strong>&nbsp;表示:</p>
<pre><code class="hljs php"><span class="hljs-class"><span class="hljs-keyword">interface <span class="hljs-title">ILink {
description?: string;
id?: number;
url: string;
}

<span class="hljs-class"><span class="hljs-keyword">interface <span class="hljs-title">IPost <span class="hljs-keyword">extends <span class="hljs-title">ILink {
title: string;
body: string;
}
</span></span></span></span></span></span></span></span></code></pre>
<p>现在,IPost&nbsp;类型的对象都将具有可选的属性&nbsp;description、id、url和必填的属性&nbsp;title&nbsp;和body:</p>
<pre><code class="hljs php"><span class="hljs-class"><span class="hljs-keyword">interface <span class="hljs-title">ILink {
description?: string;
id?: number;
url: string;
}

<span class="hljs-class"><span class="hljs-keyword">interface <span class="hljs-title">IPost <span class="hljs-keyword">extends <span class="hljs-title">ILink {
title: string;
body: string;
}

<span class="hljs-keyword">const post1: IPost = {
description:
    <span class="hljs-string">"TypeScript tutorial for beginners is a tutorial for all the <span class="hljs-string">JavaScript</span><span class="hljs-string"> developers ...",
id: <span class="hljs-number">1,
url: <span class="hljs-string">"www.valentinog.com/typescript/",
title: <span class="hljs-string">"TypeScript tutorial for beginners",
body: <span class="hljs-string">"Some stuff here!"
};
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>当像&nbsp;post1&nbsp;这样的对象使用一个接口时,我们说&nbsp;post1&nbsp;实现了该接口中定义的属性。</p>
<p>扩展接口意味着借用其属性并扩展它们以实现代码重用。当然 TypeScript 接口还也可以描述函数,稍后会看到。</p>
<p>&nbsp;</p>
<h2 id="12">索引</h2>
<p>JS 对象是键/值对的容器。 如下有一个简单的对象:</p>
<pre><code class="hljs php"><span class="hljs-keyword">const paolo = {
name: <span class="hljs-string">"Paolo",
city: <span class="hljs-string">"Siena",
age: <span class="hljs-number">44
};
</span></span></span></span></code></pre>
<p>我们可以使用点语法访问任何键的值:</p>
<pre><code class="hljs css"><span class="hljs-selector-tag">console<span class="hljs-selector-class">.log(<span class="hljs-selector-tag">paolo<span class="hljs-selector-class">.city);
</span></span></span></span></code></pre>
<p>现在假设键是动态的,我们可以把它放在一个变量中,然后在括号中引用它</p>
<pre><code class="hljs javascript"><span class="hljs-keyword">const paolo = {
<span class="hljs-attr">name: <span class="hljs-string">"Paolo",
<span class="hljs-attr">city: <span class="hljs-string">"Siena",
<span class="hljs-attr">age: <span class="hljs-number">44
};

<span class="hljs-keyword">const key = <span class="hljs-string">"city";

<span class="hljs-built_in">console.log(paolo);
</span></span></span></span></span></span></span></span></span></span></code></pre>
<p>现在咱们添加另一个对象,将它们都放到一个数组中,并使用filter方法对数组进行筛选,就像我们在&nbsp;<strong>filterByTerm.js</strong>&nbsp;中所做的那样。但这一次<strong>键</strong>是动态传递的,因此可以过滤任何对象<strong>键</strong>:</p>
<pre><code class="hljs php"><span class="hljs-keyword">const paolo = {
name: <span class="hljs-string">"Paolo",
city: <span class="hljs-string">"Siena",
age: <span class="hljs-number">44
};

<span class="hljs-keyword">const tom = {
name: <span class="hljs-string">"Tom",
city: <span class="hljs-string">"Munich",
age: <span class="hljs-number">33
};

<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterPerson<span class="hljs-params">(arr, term, key) {
<span class="hljs-keyword">return arr.filter(<span class="hljs-function"><span class="hljs-keyword">function<span class="hljs-params">(person) {
    <span class="hljs-keyword">return person.match(term);
});
}

filterPerson(, <span class="hljs-string">"Siena", <span class="hljs-string">"city");
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>这是比较重要的一行行:</p>
<pre><code class="hljs css"><span class="hljs-selector-tag">return <span class="hljs-selector-tag">person<span class="hljs-selector-attr"><span class="hljs-selector-class">.match(<span class="hljs-selector-tag">term);
</span></span></span></span></span></code></pre>
<p>能行吗 是的,因为 JS 不在乎&nbsp;paolo&nbsp;或&nbsp;tom&nbsp;是否可通过动态&nbsp;&nbsp;进行“索引化”。 那在 TS 又是怎么样的呢?</p>
<p>在下一部分中,我们将使用动态键使&nbsp;filterByTerm&nbsp;更加灵活。</p>
<p>&nbsp;</p>
<h2 id="13">接口可以有索引</h2>
<p>让我们回到&nbsp;<strong>filterByTerm.ts</strong>&nbsp;中&nbsp;<strong>filterByTerm</strong>&nbsp;函数</p>
<pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm(<span class="hljs-params">input: Array&lt;ILink&gt;, searchTerm: string) {
<span class="hljs-keyword">if (!searchTerm) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"searchTerm 不能为空");
<span class="hljs-keyword">if (!input.length) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"input 不能为空");
<span class="hljs-keyword">const regex = <span class="hljs-keyword">new <span class="hljs-built_in">RegExp(searchTerm, <span class="hljs-string">"i");
<span class="hljs-keyword">return input.filter(<span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">arrayElement) {
    <span class="hljs-keyword">return arrayElement.url.match(regex);
});
}
</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;ILink,咱们都使用硬编码方式将属性&nbsp;url&nbsp;与正则表达式相匹配。我们希望使动态属性(也就是键)让代码更灵活:</p>
<pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm(<span class="hljs-params">
input: Array&lt;ILink&gt;,
searchTerm: string,
lookupKey: string = <span class="hljs-string">"url"
) {
<span class="hljs-keyword">if (!searchTerm) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"searchTerm 不能为空");
<span class="hljs-keyword">if (!input.length) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"input 不能为空");
<span class="hljs-keyword">const regex = <span class="hljs-keyword">new <span class="hljs-built_in">RegExp(searchTerm, <span class="hljs-string">"i");
<span class="hljs-keyword">return input.filter(<span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">arrayElement) {
    <span class="hljs-keyword">return arrayElement.match(regex);
});
}
</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>lookupKey&nbsp;是动态键,这是给它分配了默认参数&nbsp;“url”。 接着编译代码:</p>
<pre><code class="hljs nginx"><span class="hljs-attribute">npm run tsc
</span></code></pre>
<p>当然会报错:</p>
<pre><code class="hljs nginx"><span class="hljs-attribute">error TS7053: Element implicitly has an <span class="hljs-string">'any' type because expression of type <span class="hljs-string">'string' can<span class="hljs-string">'t be used to index type 'ILink<span class="hljs-string">'.
No index signature with a parameter of type 'string<span class="hljs-string">' was found on type 'ILink<span class="hljs-string">'.
</span></span></span></span></span></span></span></code></pre>
<p>出错行:</p>
<pre><code class="hljs css"><span class="hljs-selector-tag">return <span class="hljs-selector-tag">arrayElement<span class="hljs-selector-attr"><span class="hljs-selector-class">.match(<span class="hljs-selector-tag">regex);
</span></span></span></span></span></code></pre>
<p>元素隐式具有&nbsp;"any"&nbsp;类型,因为类型&nbsp;<strong>“ILink”</strong>&nbsp;没有索引签名,需要你添加一个索引到对象的接口,这很容易解决。</p>
<p>转到接口&nbsp;<strong>ILink</strong>&nbsp;并添加索引:</p>
<pre><code class="hljs php"><span class="hljs-class"><span class="hljs-keyword">interface <span class="hljs-title">ILink {
description?: string;
id?: number;
url: string;
: string
}
</span></span></span></code></pre>
<p>语法有点奇怪,但类似于对象上的动态键访问。这意味着我们可以通过类型为&nbsp;string&nbsp;的索引访问该对象的任何键,该索引反过来又返回另一个字符串。</p>
<p>不过,这样写会引发其它错误:</p>
<pre><code class="hljs javascript">error TS2411: Property <span class="hljs-string">'description' <span class="hljs-keyword">of type <span class="hljs-string">'string | undefined' is not assignable to string index type <span class="hljs-string">'string'.
error TS2411: Property <span class="hljs-string">'id' <span class="hljs-keyword">of type <span class="hljs-string">'number | undefined' is not assignable to string index type <span class="hljs-string">'string'.
</span></span></span></span></span></span></span></span></code></pre>
<p>这是因为接口上的一些属性是可选的,可能是&nbsp;undefined,而且返回类型不总是string(例如,id 是一个&nbsp;number)。</p>
<pre><code class="hljs php"><span class="hljs-class"><span class="hljs-keyword">interface <span class="hljs-title">ILink {
description?: string;
id?: number;
url: string;
: string | number | undefined;
}
</span></span></span></code></pre>
<p>这一行:</p>
<pre><code class="hljs javascript">: string | number | <span class="hljs-literal">undefined;
</span></code></pre>
<p>表示该索引是一个字符串,可以返回另一个字符串、数字或&nbsp;undefined。尝试再次编译,这里有另一个错误</p>
<pre><code class="hljs nginx"><span class="hljs-attribute">error TS2339: Property <span class="hljs-string">'match' does not exist <span class="hljs-literal">on type <span class="hljs-string">'string | number'.
return arrayElement.match(regex);
</span></span></span></span></code></pre>
<p>报的没毛病。match方法只存在字符串中 ,而且我们的索引有可能返回一个&nbsp;number。为了修正这个错误,我们可以使用&nbsp;any&nbsp;类型:</p>
<pre><code class="hljs php"><span class="hljs-class"><span class="hljs-keyword">interface <span class="hljs-title">ILink {
description?: string;
id?: number;
url: string;
: any;
}
</span></span></span></code></pre>
<p>再次编译通过。</p>
<p>&nbsp;</p>
<h2 id="14">函数的返回类型</h2>
<p>到目前为止有很多新东西。现在来看看 TypeScript 的另一个有用的特性<strong>:函数的返回类型</strong>。</p>
<p>回到&nbsp;filterByTerm&nbsp;函数:</p>
<pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm(<span class="hljs-params">
input: Array&lt;ILink&gt;,
searchTerm: string,
lookupKey: string = <span class="hljs-string">"url"
) {
<span class="hljs-keyword">if (!searchTerm) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"searchTerm 不能为空");
<span class="hljs-keyword">if (!input.length) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"input 不能为空");
<span class="hljs-keyword">const regex = <span class="hljs-keyword">new <span class="hljs-built_in">RegExp(searchTerm, <span class="hljs-string">"i");
<span class="hljs-keyword">return input.filter(<span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">arrayElement) {
    <span class="hljs-keyword">return arrayElement.match(regex);
});
}
</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;<strong>ILink</strong>&nbsp;数组和搜索词string3,则如预期的那样返回一个对象数组:</p>
<pre><code class="hljs php">filterByTerm(arrOfLinks, <span class="hljs-string">"string3");

<span class="hljs-comment">// EXPECTED OUTPUT:
<span class="hljs-comment">// [ { url: 'string3' } ]
</span></span></span></code></pre>
<p>但现在考虑一个更改的变体:</p>
<pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm(<span class="hljs-params">
input: Array&lt;ILink&gt;,
searchTerm: string,
lookupKey: string = <span class="hljs-string">"url"
) {
<span class="hljs-keyword">if (!searchTerm) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"searchTerm cannot be empty");
<span class="hljs-keyword">if (!input.length) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"input cannot be empty");
<span class="hljs-keyword">const regex = <span class="hljs-keyword">new <span class="hljs-built_in">RegExp(searchTerm, <span class="hljs-string">"i");
<span class="hljs-keyword">return input
    .filter(<span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">arrayElement) {
      <span class="hljs-keyword">return arrayElement.match(regex);
    })
    .toString();
}
</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;ILink&nbsp;数组和搜索词&nbsp;string3,它将返回&nbsp;</p>
<pre><code class="hljs php">filterByTerm(arrOfLinks, <span class="hljs-string">"string3");

<span class="hljs-comment">// WRONG OUTPUT:
<span class="hljs-comment">//
</span></span></span></code></pre>
<p>该函数没有按照预期工作,如果对 JS 隐式类型转换不清楚就很难发现问题。幸运的是,TypeScript 可以捕获这些错误,就像你在编辑器中写的那样。</p>
<p>修正如下:</p>
<pre><code class="hljs php"><span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm<span class="hljs-params">(<span class="hljs-comment">/* 省略 */): <span class="hljs-title">Array&lt;<span class="hljs-title">ILink&gt; {
<span class="hljs-comment">/* 省略 */
}
</span></span></span></span></span></span></span></span></code></pre>
<p>它是如何工作的? 通过在函数体之前添加类型注释,告诉 TypeScript 期望另一个数组作为返回值。现在这个bug 很容易被发现。</p>
<pre><code class="hljs javascript">interface ILink {
description?: string;
id?: number;
url: string;
: any;
}

<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm(<span class="hljs-params">
input: Array&lt;ILink&gt;,
searchTerm: string,
lookupKey: string = <span class="hljs-string">"url"
): <span class="hljs-title">Array&lt;<span class="hljs-title">ILink&gt; {
<span class="hljs-keyword">if (!searchTerm) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"searchTerm cannot be empty");
<span class="hljs-keyword">if (!input.length) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"input cannot be empty");
<span class="hljs-keyword">const regex = <span class="hljs-keyword">new <span class="hljs-built_in">RegExp(searchTerm, <span class="hljs-string">"i");
<span class="hljs-keyword">return input
    .filter(<span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">arrayElement) {
      <span class="hljs-keyword">return arrayElement.match(regex);
    })
    .toString();
}

<span class="hljs-keyword">const obj1: ILink = { <span class="hljs-attr">url: <span class="hljs-string">"string1" };
<span class="hljs-keyword">const obj2: ILink = { <span class="hljs-attr">url: <span class="hljs-string">"string2" };
<span class="hljs-keyword">const obj3: ILink = { <span class="hljs-attr">url: <span class="hljs-string">"string3" };

<span class="hljs-keyword">const arrOfLinks: <span class="hljs-built_in">Array&lt;ILink&gt; = ;

filterByTerm(arrOfLinks, <span class="hljs-string">"string3");
</span></span></span></span></span></span></span></span></span></span></span></span></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><code class="hljs nginx"><span class="hljs-attribute">error TS2322: Type <span class="hljs-string">'string' is not assignable to type <span class="hljs-string">'ILink[]'.
</span></span></span></code></pre>
<p>咱们希望返回值的是&nbsp;ILink&nbsp;数组,而不是字符串。要修复此错误,从末尾删除&nbsp;.tostring()&nbsp;并重新编译代码就行了。</p>
<p>&nbsp;</p>
<h2 id="15">类型别名 vs 接口</h2>
<p>到目前为止,我们已经将接口视为描述对象和自定义类型的工具。但是通过其他人的代码,你可能也注意到了关键字的&nbsp;<strong>type</strong>。</p>
<p>显然,<strong>interface</strong>&nbsp;和 type 在 TypeScript 中可以互换使用,但是它们在许多方面有所不同,这就是TypeScript 给初学者的困惑。</p>
<p>请记住: TypeScript 中的接口描述是某个东西的结构,大多数情况下是一个复杂的对象。</p>
<p>另一方面,type&nbsp;也可以用来描述自定义的结构,但它只是一个别名,或者换句话说,是自定义类型的标签。例如,设想一个有两个字段的接口,其中一个是布尔型、数字型和字符串型的<strong>联合类型</strong>。</p>
<pre><code class="hljs css"><span class="hljs-selector-tag">interface <span class="hljs-selector-tag">IExample {
<span class="hljs-attribute">authenticated: boolean | number | string;
<span class="hljs-attribute">name: string;
}
</span></span></span></span></code></pre>
<p>例如,使用&nbsp;<strong>type 别名</strong>&nbsp;可以提取自定义联合类型,并创建名为&nbsp;<strong>Authenticated</strong>&nbsp;的标签</p>
<pre><code class="hljs php">type Authenticated = boolean | number | string;

<span class="hljs-class"><span class="hljs-keyword">interface <span class="hljs-title">IExample {
authenticated: Authenticated;
name: string;
}
</span></span></span></code></pre>
<p>通过这种方式,咱可以隔离所做的更改,就不必在整个代码库中复制/粘贴&nbsp;<strong>联合类型</strong>。</p>
<p>如果要将&nbsp;<strong>type</strong>&nbsp;应用上面示例(filterByTerm),创建一个名为&nbsp;<strong>ILinks</strong>&nbsp;的新标签,并将&nbsp;<strong>Array &lt;ILink&gt;</strong>&nbsp;分配给它。 这样,就可以引用前者:</p>
<pre><code class="hljs javascript"><span class="hljs-comment">// the new label
type ILinks = <span class="hljs-built_in">Array&lt;ILink&gt;;
<span class="hljs-comment">// the new label

<span class="hljs-function"><span class="hljs-keyword">function <span class="hljs-title">filterByTerm(<span class="hljs-params">
input: ILinks,
searchTerm: string,
lookupKey: string = <span class="hljs-string">"url"
): <span class="hljs-title">ILinks {
<span class="hljs-keyword">if (!searchTerm) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"searchTerm 不能为空");
<span class="hljs-keyword">if (!input.length) <span class="hljs-keyword">throw <span class="hljs-built_in">Error(<span class="hljs-string">"input 不能为空");
<span class="hljs-keyword">const regex = <span class="hljs-keyword">new <span class="hljs-built_in">RegExp(searchTerm, <span class="hljs-string">"i");
<span class="hljs-keyword">return input.filter(<span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">arrayElement) {
    <span class="hljs-keyword">return arrayElement.match(regex);
});
}

<span class="hljs-keyword">const obj1: ILink = { <span class="hljs-attr">url: <span class="hljs-string">"string1" };
<span class="hljs-keyword">const obj2: ILink = { <span class="hljs-attr">url: <span class="hljs-string">"string2" };
<span class="hljs-keyword">const obj3: ILink = { <span class="hljs-attr">url: <span class="hljs-string">"string3" };

<span class="hljs-keyword">const arrOfLinks: ILinks = ;

filterByTerm(arrOfLinks, <span class="hljs-string">"string3");
</span></span></span></span></span></span></span></span></span></span></span></span></span></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;type&nbsp;用法最好事例。那么在&nbsp;<strong>interface</strong>&nbsp;和&nbsp;<strong>type</strong>&nbsp;之间使用哪个呢? 我更喜欢复杂对象的接口。TypeScript 文档&nbsp;也建议了。</p>
<p>一个软件的理想状态是可以扩展,因此,如果可能,应始终在类型别名上使用接口。</p>
<p><span style="position: relative; left: -100000px">资源搜索网站大全 https://www.renrenfan.com.cn</span> <span style="position: relative; left: -100000px">广州VI设计公司https://www.houdianzi.com</span></p>
<h2 id="16">更多关于接口和对象的知识点</h2>
<p>函数是 JS 中的一等公民,而对象是该语言中最重要的实体。</p>
<p>对象大多是键/值对的容器,它们也可以保存函数,这一点也不奇怪。当一个函数位于一个对象内部时,它可以通过关键字&nbsp;this&nbsp;访问“宿主”对象:</p>
<pre><code class="hljs javascript"><span class="hljs-keyword">const tom = {
<span class="hljs-attr">name: <span class="hljs-string">"web<span class="hljs-string">前端</span><span class="hljs-string">",
<span class="hljs-attr">city: <span class="hljs-string">"厦门",
<span class="hljs-attr">age: <span class="hljs-number">26,
<span class="hljs-attr">printDetails: <span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">) {
    <span class="hljs-built_in">console.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">this.name} - <span class="hljs-subst">${<span class="hljs-keyword">this.city}`);
}
};
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>到目前为止,咱们已经看到 TypeScript 接口应用于简单对象,用于描述字符串和数字。 但是他们可以做的更多。 举个例, 使用以下代码创建一个名为&nbsp;<strong>interfaces-functions.ts</strong>&nbsp;的新文件:</p>
<pre><code class="hljs javascript"><span class="hljs-keyword">const tom = {
<span class="hljs-attr">name: <span class="hljs-string">"web<span class="hljs-string">前端</span><span class="hljs-string">",
<span class="hljs-attr">city: <span class="hljs-string">"厦门",
<span class="hljs-attr">age: <span class="hljs-number">26,
<span class="hljs-attr">printDetails: <span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">) {
    <span class="hljs-built_in">console.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">this.name} - <span class="hljs-subst">${<span class="hljs-keyword">this.city}`);
}
};

</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>这是一个 JS 对象,咱们使用接口&nbsp;<strong>IPerson</strong>&nbsp;给它加上类型:</p>
<pre><code class="hljs javascript">interface IPerson {
<span class="hljs-attr">name: string;
city: string;
age: number;
}

<span class="hljs-keyword">const tom: IPerson = {
<span class="hljs-attr">name: <span class="hljs-string">"web前端",
<span class="hljs-attr">city: <span class="hljs-string">"厦门",
<span class="hljs-attr">age: <span class="hljs-number">26,
<span class="hljs-attr">printDetails: <span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">) {
    <span class="hljs-built_in">console.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">this.name} - <span class="hljs-subst">${<span class="hljs-keyword">this.city}`);
}
};
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>编译代码并查看报错信息:</p>
<pre><code class="hljs php">interfaces-functions.ts:<span class="hljs-number">11:<span class="hljs-number">3 - error TS2322: Type <span class="hljs-string">'{ name: string; city: string; age: number; printDetails: () =&gt; void; }' is not assignable to type <span class="hljs-string">'IPerson'.
Object literal may only specify known properties, <span class="hljs-keyword">and <span class="hljs-string">'printDetails' does not exist in type <span class="hljs-string">'IPerson'.
</span></span></span></span></span></span></span></code></pre>
<p><strong>IPerson</strong>&nbsp;没有任何名为printDetails的属性,但更重要的是它应该是一个函数。幸运的是,TypeScript 接口也可以描述函数。如下所示:</p>
<pre><code class="hljs php"><span class="hljs-class"><span class="hljs-keyword">interface <span class="hljs-title">IPerson {
name: string;
city: string;
age: number;
printDetails(): void;
}
</span></span></span></code></pre>
<p>在这里,我们添加了类型函数的属性&nbsp;printDetails,返回&nbsp;void。&nbsp;void&nbsp;表示不返回任何值。</p>
<p>实际上,打印到控制台的函数不会返回任何内容。 如果要从&nbsp;printDetails&nbsp;返回字符串,则可以将返回类型调整为&nbsp;string:</p>
<pre><code class="hljs javascript">interface IPerson {
<span class="hljs-attr">name: string;
city: string;
age: number;
printDetails(): string;
}

<span class="hljs-keyword">const tom: IPerson = {
<span class="hljs-attr">name: <span class="hljs-string">"web前端",
<span class="hljs-attr">city: <span class="hljs-string">"厦门",
<span class="hljs-attr">age: <span class="hljs-number">26,
<span class="hljs-attr">printDetails: <span class="hljs-function"><span class="hljs-keyword">function(<span class="hljs-params">) {
    <span class="hljs-keyword">return <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-keyword">this.name} - <span class="hljs-subst">${<span class="hljs-keyword">this.city}`;
}
};

</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
<p>如果函数有参数呢? 在接口中,可以为它们添加类型注释</p>
<pre><code class="hljs php"><span class="hljs-class"><span class="hljs-keyword">interface <span class="hljs-title">IPerson {
name: string;
city: string;
age: number;
printDetails(): string;
anotherFunc(a: number, b: number): number;
}</span></span></span></code></pre>
<p>&nbsp;</p>
<h2 id="17">总结</h2>
<p>这里无法涵盖每一个 TypeScript 特性。例如,省略[了ES2015类及其与接口或更高级类型]6的关系。当然后续会持续介绍。</p>
<p>在这个 TypeScript 教程中,讲了:</p>
<ul>
<li>变量,函数参数和返回值的类型注释</li>
<li>接口</li>
<li>自定义类型</li>
<li>类型别名
<p>TS 帮助咱们减少一些 JS 代码隐藏的错误。需要重复的是,TypeScript 不能替代测试。 蛤它确实是一个有价值的工具,一开始很难掌握,但完全值得投资。</p>
</li>
</ul><br><br>
来源:https://www.cnblogs.com/xiaonian8/p/14113471.html
頁: [1]
查看完整版本: TypeScript:入门TS