<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Theoda - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Theoda - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 06 Jun 2026 19:41:53 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/author/theoda/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 面向对象的编程概念：从 0 到 1 使用对象 ]]>
                </title>
                <description>
                    <![CDATA[ 面向对象编程是最为广泛使用的编程范式之一，它的名字就定义了它的工作原理，“面向对象”——“对象”起着重要的作用，操作对象并得到结果是面向对象编程的最终目标。 使用面向对象编程范式的语言称为面向对象编程语言，它们大多是高级语言，例如：  * Java  * C#  * Python — Python 既是脚本语言、结构化语言，也是面向对象语言。 为了进行面向对象编程，我们会使用一些面向对象的概念，它们简化了面向对象编程，并为其增添了更多价值。 这些概念如下：  * 封装  * 抽象  * 多态  * 继承 在了解这些概念之前，我们需要了解“类”和“对象”。 对象 是面向对象编程中基本的运行实体。日常生活中我们就能看到很多对象，如电视、手机、狗、人、汽车，以及其他有生命或无生命的对象。这些都可以被描述为面向对象编程中的对象。 类是一张蓝图或一个原型，它定义了特定一类对象共有的变量/属性和方法/函数，它是一种逻辑组件。 简单来说，“类”是用户定义的数据类型，“对象”是类的变量。构造了“类”以后，我们可以根据需要创建任意数目的对象。 例如，我们构造一个名为“树” (Tree ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/object-oriented-concepts/</link>
                <guid isPermaLink="false">5dc50e47ca1efa04e196a40b</guid>
                
                <dc:creator>
                    <![CDATA[ Theoda ]]>
                </dc:creator>
                <pubDate>Fri, 15 May 2020 09:20:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/04/photo-1573331592635-f658507c1e8c.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>面向对象编程是最为广泛使用的编程范式之一，它的名字就定义了它的工作原理，“面向对象”——“对象”起着重要的作用，操作对象并得到结果是面向对象编程的最终目标。</p><p>使用面向对象编程范式的语言称为面向对象编程语言，它们大多是高级语言，例如：</p><ul><li>Java</li><li>C#</li><li>Python — Python 既是脚本语言、结构化语言，也是面向对象语言。</li></ul><p>为了进行面向对象编程，我们会使用一些<strong>面向对象的概念</strong>，它们简化了面向对象编程，并为其增添了更多价值。</p><p>这些概念如下：</p><ul><li>封装</li><li>抽象</li><li>多态</li><li>继承</li></ul><p>在了解这些概念之前，我们需要了解“类”和“对象”。</p><p><strong>对象</strong>是面向对象编程中基本的运行实体。日常生活中我们就能看到很多对象，如电视、手机、狗、人、汽车，以及其他有生命或无生命的对象。这些都可以被描述为面向对象编程中的对象。</p><p><strong>类</strong>是一张蓝图或一个原型，它定义了特定一类对象共有的变量/属性和方法/函数，它是一种逻辑组件。</p><p>简单来说，“类”是<strong>用户定义的</strong>数据类型，“对象”是类的<strong>变量</strong>。构造了“类”以后，我们可以根据需要创建任意数目的对象。</p><p>例如，我们构造一个名为“树” (Tree) 的类，“树”这个类的状态/属性就是：</p><ul><li>树的名称 (Name)</li><li>树的年龄 (Age)</li><li>树的类型 (Type)</li><li>树的高度 (Height)</li></ul><p>状态/属性用于定义对象的属性，也就是说，<strong>状态/成员/属性</strong>都代表相同的东西。</p><p>“树”的动作行为可以是：</p><ul><li>结果实</li><li>落叶</li><li>从根部吸收水分运往上部</li><li>形成树荫</li></ul><p>然后，我们可以用“树”类定义一个变量 Mango (芒果树) 。我们可以通过创建 Mango 对象来存储和访问我们之前为“树”类定义的所有属性和行为。</p><p>用“树” (Tree) 类创建 Mango 这个对象的语法是：</p><p><strong>Tree</strong> &nbsp;Mango;</p><h3 id="-">封装</h3><p>你食用过彩色外壳的胶囊吗？</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/pills_tablets_medicine_capsule_heal_drugs_pharmacy_nutrient_additives-859474.jpg-d.jpeg" class="kg-image" alt="pills_tablets_medicine_capsule_heal_drugs_pharmacy_nutrient_additives-859474.jpg-d" width="600" height="400" loading="lazy"></figure><p>药物是被封装好存进胶囊里的，里面的药物存放得非常安全，肉眼是看不到的，想要知道里面是什么必须得拆开外壳。</p><p>相似地，所有<strong>数据成员（变量/属性/成员）</strong>和 <strong>行为（函数/方法）</strong>都被放到一起，并封装起来。“类”就是“封装”最好的例子。</p><p>打个比方，你正在药店买一些处方药，你把处方交给药师，TA 会帮你在店里拿好药。</p><p>在这个场景中，药品——充当了 变量/成员/属性，药师——作为成员函数/方法，TA 把药拿给你，你——外部的应用程序或其他软件的代码</p><figure class="kg-card kg-image-card"><img src="https://docs.google.com/drawings/d/spRw5P3ZQcCXoRMBDaWoceg/image?w=431&amp;h=300&amp;rev=30&amp;ac=1&amp;parent=1co9lGXLHg9idixOA7Dssbv3whQYlkF3jd5n9wWo0Oaw" class="kg-image" alt="image?w=431&amp;h=300&amp;rev=30&amp;ac=1&amp;parent=1co9lGXLHg9idixOA7Dssbv3whQYlkF3jd5n9wWo0Oaw" width="600" height="400" loading="lazy"></figure><p>通过封装可以限制外部代码访问内部的数据，比如你可以在实现代码的时候这么定义：只有在类中定义的函数才能访问类的成员。程序员是可以在开发过程中指定成员变量的可访问性的，而不是像过程化语言那样使所有变量全局化。这种可访问性的控制也称为<strong>信息隐藏</strong>。</p><p><strong>封装允许公开必要的东西，也能把重要的东西对外界藏起来</strong>。因此，类隐藏的部分就像<strong>封装</strong>，显露的部分像<strong>抽象</strong>。</p><h3 id="--1">抽象</h3><p>通过抽象，我们不用解释太多就可以显露类的必要特性。今天早上我想泡杯热茶，要用水壶烧水，我简简单单按下<strong>启动</strong>按钮烧水，我不想知道水壶内部怎么工作的，我不想知道它有什么高电阻、电阻产热、水沸腾之类的，反正我能简单地烧好水就行了。因此，按下“启动”按钮烧水就被称为“抽象”。</p><p>类似地，通过遥控器的帮助，我们用简单的几个键就能操控电视。</p><p><strong>数据抽象</strong>是一种编程技巧，它取决于<strong>接口</strong>和<strong>具体实现</strong>能否分离开来。</p><p>在面向对象编程时，数据抽象的概念可以来自两种类型的类：</p><ul><li>抽象类：(0-100)% 的抽象</li><li>接口类：100% 的抽象</li></ul><h3 id="--2">继承</h3><p>顾名思义，每个人从出生起都有从家庭遗传的特征，你可能会有祖父母或父母的一些特征，这也正是“继承”在面向对象编程中的作用。</p><figure class="kg-card kg-image-card"><img src="https://docs.google.com/drawings/d/sO6CPcUTCRHxWv3ghO23f5g/image?w=424&amp;h=268&amp;rev=130&amp;ac=1&amp;parent=1co9lGXLHg9idixOA7Dssbv3whQYlkF3jd5n9wWo0Oaw" class="kg-image" alt="image?w=424&amp;h=268&amp;rev=130&amp;ac=1&amp;parent=1co9lGXLHg9idixOA7Dssbv3whQYlkF3jd5n9wWo0Oaw" width="600" height="400" loading="lazy"></figure><p>类可以拥有它的“父类”的属性和方法，父类也被称为基类，继承基类的类称为“派生类”。继承是面向对象编程最强大的功能了。</p><p>有效地使用继承可以节省大量时间，还能减少程序中的错误，进而为我们提高工作质量和生产力。</p><p>继承有不同的类型：</p><ul><li>单继承（Single Inheritance）</li><li>分层继承（Hierarchical Inheritance）</li><li>多继承（Multiple Inheritance）</li><li>多层继承（Multi Level Inheritance）</li></ul><h3 id="--3">多态</h3><p>Polymorphism（多态）是一个<strong>希腊词语</strong>，指的是具有多种形态或超载的能力。比如说我们都知道的编程中的<strong>函数</strong>，它们在括号内接受不同的参数，多态性也只是具有相同名字的函数，传递不同的参数来得到结果。</p><p>以名为 sum 的函数为例，它可以带 2 或 3 个参数：</p><p>sum(3,4) sum(10,23,56)</p><p>通过提供适当数量的参数来调用这些函数，将根据被调用函数的设计方式给出相应结果。</p><p><strong><em>程序如何区分上述情况，来决定执行哪个函数呢？</em></strong></p><p>面向对象编程中有一个名为<strong>动态绑定</strong>的功能，会根据程序的执行来调用实际的函数。当程序执行 2 个参数的函数时，编译器就会用 2 个参数的函数来执行，3 个参数的函数同理。</p><p>在实际运行之前，编译器并不知道到底需要调用哪个函数，这取决于程序会如何调用函数名。这也被称为<strong>迟绑定。</strong></p><h3 id="--4">面向对象编程的用途</h3><ul><li>使用<strong>封装</strong>（信息隐藏）可以对外部隐藏数据</li><li>使用<strong>继承</strong>可以重用代码</li><li>使用<strong>多态</strong>可以重载操作符/方法/函数，即相同的函数名或操作符名称可用于多种任务</li><li>数据抽象可以用<strong>抽象</strong>实现</li><li>项目易于迁移（可以从小项目转换成大项目）</li><li>同一项目分工</li><li>软件复杂性可控</li></ul><h3 id="--5">面向对象编程的应用领域</h3><ul><li>人工智能与专家系统</li><li>企业级应用</li><li>神经网络与并行编程</li><li>办公自动化系统</li></ul><p>希望你阅读后能对面向对象概念有简要的了解，也希望我能在将来的文章中写到如何进行面向对象编程。</p><p>原文：<a href="https://www.freecodecamp.org/news/object-oriented-concepts/">https://www.freecodecamp.org/news/object-oriented-concepts/</a>，作者：Parathan Thiyagalingam</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ TypeScript 完全手册 ]]>
                </title>
                <description>
                    <![CDATA[ Stack Overflow 在 90,000 名开发者中开展了 一项调查 [https://insights.stackoverflow.com/survey/2019#most-loved-dreaded-and-wanted] ，结果显示 TypeScript 是人们最想学习的工具之一。 在过去几年中，TypeScript 的热门程度、社区规模和使用率都在不断提高。如今，甚至 Facebook 正将 Jest 项目转移至 TypeScript [https://github.com/facebook/jest/pull/7554#issuecomment-454358729]。 什么是 TypeScript？ TypeScript 是 JavaScript 的超集，具有静态类型特性，旨在简化大型 JavaScript 应用程序的开发，也被称为 JavaScript that scales（可拓展的 JavaScript）。 为什么要用 TypeScript？ JavaScript 在过去几年中快速发展，成为客户端和服务器端最通用的跨平台语言。 但 JavaScript 本 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/the-definitive-typescript-handbook/</link>
                <guid isPermaLink="false">5d5f855afbfdee429dc5f944</guid>
                
                <dc:creator>
                    <![CDATA[ Theoda ]]>
                </dc:creator>
                <pubDate>Sat, 15 Feb 2020 07:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2019/08/ts-1-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Stack Overflow 在 90,000 名开发者中开展了 <a href="https://insights.stackoverflow.com/survey/2019#most-loved-dreaded-and-wanted">一项调查</a>，结果显示 TypeScript 是人们最想学习的工具之一。</p>
<p>在过去几年中，TypeScript 的热门程度、社区规模和使用率都在不断提高。如今，甚至 <a href="https://github.com/facebook/jest/pull/7554#issuecomment-454358729">Facebook 正将 Jest 项目转移至 TypeScript</a>。</p>
<h1 id="typescript"><strong>什么是 TypeScript？</strong></h1>
<p>TypeScript 是 JavaScript 的超集，具有静态类型特性，旨在简化大型 JavaScript 应用程序的开发，也被称为 <strong>JavaScript that scales</strong>（<strong>可拓展的 JavaScript</strong>）。</p>
<h2 id="typescript"><strong>为什么要用 TypeScript？</strong></h2>
<p>JavaScript 在过去几年中快速发展，成为客户端和服务器端最通用的跨平台语言。</p>
<p>但 JavaScript 本意并不用于大型应用开发。它是一种没有类型系统的动态语言，也就是说，变量的值可以是任何类型（例如字符串或布尔值）。</p>
<p>而类型系统能够提高代码质量和可读性，使代码库更易于维护或重构。更重要的是它可以在编译时就捕获错误，而不是在运行时才捕获。</p>
<p>而 JavaScript 并没有类型系统，所以一个大型开发团队难以使用 JavaScript 构建复杂的应用程序。</p>
<p>而 TypeScript 能在编译时检查不同部分代码的正确性。在编译时检查出错误，便于开发者发现错误的位置和具体问题。如果运行时才检查出错误，则需要跟踪复杂的堆栈，花费大量时间进行调试。</p>
<h2 id="typescript"><strong>TypeScript 的优点</strong></h2>
<ol>
<li>在开发周期中能更早地捕获潜在的错误。</li>
<li>管理大型代码库。</li>
<li>更易于重构。</li>
<li>更易于团队合作：代码的耦合性越强，不同开发人员访问代码库时越不容易造成无意破坏。</li>
<li>文档特性：类型本身就是一种文档信息，方便日后开发者本人或者其他开发者查询。</li>
</ol>
<h2 id="typescript"><strong>TypeScript 的缺点</strong></h2>
<ol>
<li>需要额外的学习：<strong>需要在短期放缓进度与长期提高效率间进行权衡。</strong></li>
<li>类型错误可能多种多样。</li>
<li>配置极大地影响运行。</li>
</ol>
<h1 id=""><strong>类型</strong></h1>
<h2 id="boolean"><strong>Boolean (布尔值)</strong></h2>
<pre><code class="language-typescript">const isLoading: boolean = false;
</code></pre>
<h2 id="number"><strong>Number (数字)</strong></h2>
<pre><code class="language-typescript">const decimal: number = 8;
const binary: number = 0b110;
</code></pre>
<h2 id="string"><strong>String (字符串)</strong></h2>
<pre><code class="language-typescript">const fruit: string = "orange";
</code></pre>
<h2 id="array"><strong>Array (数组)</strong></h2>
<p>数组可以写成下面两种形式：</p>
<pre><code class="language-typescript">// 最常见的方式
let firstFivePrimes: number[] = [2, 3, 5, 7, 11];
// 不太常见的方式：使用泛型 (稍后介绍)
let firstFivePrimes2: Array&lt;number&gt; = [2, 3, 5, 7, 11];
</code></pre>
<h2 id="tuple"><strong>Tuple (元组)</strong></h2>
<p>Tuple 类型表示一种组织好的数组，元素的类型预先知道，并且数量固定。这意味着你有可能得到错误提示：</p>
<pre><code class="language-typescript">let contact: [string, number] = ['John', 954683];
contact = ['Ana', 842903, 'extra argument']  /* Error! 
Type '[string, number, string]' is not assignable to type '[string, number]'. */
</code></pre>
<h2 id="any"><strong>Any (任意值)</strong></h2>
<p><code>any</code> 与类型系统中的任何类型都兼容。意味着可以将任何内容赋值给它，也可以将它赋值给任何类型。它能让你避开类型检查。</p>
<pre><code class="language-typescript">let variable: any = 'a string';
variable = 5;
variable = false;
variable.someRandomMethod(); /* 行吧，
也许运行的时候 someRandomMethod 是存在的 */
</code></pre>
<h2 id="void"><strong>Void (空值)</strong></h2>
<p><code>void</code> 表示没有任何类型。它通常用作没有返回值的函数的返回类型。</p>
<pre><code class="language-typescript">function sayMyName(name: string): void {
  console.log(name);
}
sayMyName('Heisenberg');
</code></pre>
<h2 id="never"><strong>Never</strong></h2>
<p><code>never</code> 类型表示的是那些永不存在的值的类型。 例如，<code>never</code> 类型是那些总是会抛出异常、或者根本就不会有返回值的函数的返回值类型。</p>
<pre><code class="language-typescript">// 抛出异常
function error(message: string): never {
  throw new Error(message);
}

// 永远不能返回
function continuousProcess(): never {
  while (true) {
      // ...
  }
}
</code></pre>
<h2 id="nullundefined"><strong>Null 和 Undefined</strong></h2>
<p><code>undefined</code> 和 <code>null</code> 两者各自有自己的类型分别叫做 <code>undefined</code> 和 <code>null</code>。和 <code>void</code> 相似，它们的本身的类型用处不是很大，但是在联合类型中非常有用 <strong>（稍后介绍）</strong>。</p>
<pre><code class="language-typescript">type someProp = string | null | undefined;
</code></pre>
<h2 id="unknown"><strong>Unknown</strong></h2>
<p>TypeScript 3.0 引入了 unknown (未知) 类型，它是与 <code>any</code> 类型对应的安全类型。任何东西都可以赋值给 <code>unknown</code>，但 <code>unknown</code> 不能赋值给除了它本身和 <code>any</code> 以外的任何东西。在没有先断言或指定到更具体类型的情况下，不允许对 <code>unknown</code> 进行任何操作。</p>
<pre><code class="language-typescript">type I1 = unknown &amp; null;    // null
type I2 = unknown &amp; string;  // string
type U1 = unknown | null;    // unknown
type U2 = unknown | string;  // unknown
</code></pre>
<h2 id=""><strong>类型别名</strong></h2>
<p>类型别名可以为现有类型提供替代名称，以便某些地方使用。构造它的语法如下：</p>
<pre><code class="language-typescript">type Login = string;
</code></pre>
<h2 id=""><strong>联合类型</strong></h2>
<p>TypeScript 允许让一个属性具有多种数据类型，名为 union (联合) 类型。</p>
<pre><code class="language-typescript">type Password = string | number;
</code></pre>
<h2 id=""><strong>交叉类型</strong></h2>
<p>交叉类型是将多种类型叠加到一起成为一种类型。</p>
<pre><code class="language-typescript">interface Person {
  name: string;
  age: number;
}
interface Worker {
  companyId: string;
}
type Employee = Person &amp; Worker;
</code></pre>
<h1 id="interface"><strong>Interface (接口)</strong></h1>
<p>接口好似你和编译器定义契约，由你指定一个类型，预期它的属性应该是些什么类型。</p>
<p><strong>边注：接口不受 JavaScript 运行时的特性影响，它只在类型检查中会用到。</strong></p>
<ul>
<li>可以声明<strong><strong>可选属性</strong></strong>（带有 <code>?</code> 标记），意味着接口的对象可能会、也可能不会定义这些属性。</li>
<li>可以声明<strong><strong>只读属性</strong></strong>，意味着一旦为属性赋值，就无法更改。</li>
</ul>
<pre><code class="language-typescript">interface ICircle {
  readonly id: string;
  center: {
    x: number;
    y: number;
  },
  radius: number;
  color?: string;  // 可选属性
}

const circle1: ICircle = {
  id: '001',
  center: { x: 0 },
  radius: 8,
};  /* Error! Property 'y' is missing in type '{ x: number; }' 
but required in type '{ x: number; y: number; }'. */

const circle2: ICircle = {
  id: '002',
  center: { x: 0, y: 0 },
  radius: 8,
}  // 正确
</code></pre>
<h2 id=""><strong>扩展接口</strong></h2>
<p>接口可以扩展成另一个接口，或者更多接口。这使得接口的编写更具有灵活性和复用性。</p>
<pre><code class="language-typescript">interface ICircleWithArea extends ICircle {
  getArea: () =&gt; number;
}
</code></pre>
<h2 id=""><strong>实现接口</strong></h2>
<p>实现接口的类需要严格遵循接口的结构。</p>
<pre><code class="language-typescript">interface IClock {
  currentTime: Date;
  setTime(d: Date): void;
}
</code></pre>
<h1 id=""><strong>枚举</strong></h1>
<p><code>enum</code> (枚举) 用来组织一组的相关值，这些值可以是数值，也可以是字符串值。</p>
<pre><code class="language-typescript">enum CardSuit {
  Clubs,
  Diamonds,
  Hearts,
  Spades
}
let card = CardSuit.Clubs;
</code></pre>
<p>默认情况下，枚举的本质是数字。<code>enum</code> 的取值从 0 开始，以 1 递增。</p>
<p>上一个例子所生成的 JavaScript 代码如下：</p>
<pre><code class="language-typescript">var CardSuit;
(function (CardSuit) {
  CardSuit[CardSuit["Clubs"] = 0] = "Clubs";
  CardSuit[CardSuit["Diamonds"] = 1] = "Diamonds";
  CardSuit[CardSuit["Hearts"] = 2] = "Hearts";
  CardSuit[CardSuit["Spades"] = 3] = "Spades";
})(CardSuit || (CardSuit = {}));
</code></pre>
<p>或者，枚举可以用字符串值来初始化，这种方法更易读。</p>
<pre><code class="language-typescript">enum SocialMedia {
  Facebook = 'FACEBOOK',
  Twitter = 'TWITTER',
  Instagram = 'INSTAGRAM',
  LinkedIn = 'LINKEDIN'
}
</code></pre>
<h2 id=""><strong>反向映射</strong></h2>
<p><code>enum</code> 支持反向映射，也就是说，可以通过值来获得成员、成员名。</p>
<p>回顾之前 CardSuit 的例子：</p>
<pre><code class="language-typescript">const clubsAsNumber: number = CardSuit.Clubs; // 3
const clubsAsString: string = CardSuit[0];    // 'Clubs'
</code></pre>
<h1 id=""><strong>函数</strong></h1>
<p>你可以为每个参数指定一个类型，再为函数指定一个返回类型。</p>
<pre><code class="language-typescript">function add(x: number, y: number): number {
  return x + y;
}
</code></pre>
<h2 id=""><strong>函数重载</strong></h2>
<p>TypeScript 允许声明 <strong>函数重载</strong>。简单来说，可以使用多个名称相同但参数类型和返回类型不同的函数。参考下面的例子：</p>
<pre><code class="language-typescript">function padding(a: number, b?: number, c?: number, d?: any) {
  if (b === undefined &amp;&amp; c === undefined &amp;&amp; d === undefined) {
    b = c = d = a;
  }
  else if (c === undefined &amp;&amp; d === undefined) {
    c = a;
    d = b;
  }
  return {
    top: a,
    right: b,
    bottom: c,
    left: d
  };
}
</code></pre>
<p>参数的含义根据传递给函数的参数数量而变化。此外，该函数只接受一个、两个或四个参数。要构造函数重载，只需多次声明函数头就可以了。最后一个函数头真正实现了函数体，但函数外部并不能直接调用最后一个函数头。</p>
<pre><code class="language-typescript">function padding(all: number);
function padding(topAndBottom: number, leftAndRight: number);
function padding(top: number, right: number, bottom: number, left: number);
function padding(a: number, b?: number, c?: number, d?: number) {
  if (b === undefined &amp;&amp; c === undefined &amp;&amp; d === undefined) {
    b = c = d = a;
  }
  else if (c === undefined &amp;&amp; d === undefined) {
    c = a;
    d = b;
  }
  return {
    top: a,
    right: b,
    bottom: c,
    left: d
  };
}
</code></pre>
<h1 id=""><strong>类</strong></h1>
<p>你可以指定属性的类型和方法参数的类型。</p>
<pre><code class="language-typescript">class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet(name: string) {
    return `Hi ${name}, ${this.greeting}`;
  }
}
</code></pre>
<h2 id=""><strong>访问修饰符</strong></h2>
<p>Typescript 支持 <code>public</code> (公有),  <code>private</code> (私有),  <code>protected</code> (保护)  修饰符，它们决定了类成员的可访问性。</p>
<ul>
<li><code>public</code> (公有) 成员和纯 JavaScript 的成员一样，是默认的修饰符。</li>
<li><code>private</code> (私有) 成员对外界来说不可访问。</li>
<li><code>protected</code>(保护) 成员和私有成员的区别在于，它能够被继承类访问。</li>
</ul>
<pre><code class="language-markdown">| 具有访问权限     | public | protected | private |
| :------------- | :----: | :-------: | :-----: |
| 类本身          |   yes  |    yes    |   yes   |
| 派生类          |   yes  |    yes    |    no   |
| 类实例          |   yes  |     no    |    no   |
</code></pre>
<h2 id=""><strong>只读修饰符</strong></h2>
<p><code>readonly</code> (只读) 变量必须在它声明或构造时初始化。</p>
<pre><code class="language-typescript">class Spider {
  readonly name: string;
  readonly numberOfLegs: number = 8;
  constructor (theName: string) {
    this.name = theName;
  }
}
</code></pre>
<h2 id=""><strong>参数属性</strong></h2>
<p><strong>参数属性</strong>  可以放在一个地方创建并初始化成员。它通过给构造函数参数添加一个访问限定符来声明。</p>
<pre><code class="language-typescript">class Spider {
  readonly numberOfLegs: number = 8;
  constructor(readonly name: string) {
  }
}
</code></pre>
<h2 id=""><strong>抽象</strong></h2>
<p>abstract (抽象) 这个关键字可以用在抽象类上，也可以用在抽象类方法上。</p>
<ul>
<li><strong><strong>抽象类</strong></strong>  不会直接被实例化。抽象类主要用于继承，继承抽象类必须实现它所有的抽象方法。</li>
<li><strong><strong>抽象成员</strong></strong>  不包含具体实现，因此不能被直接访问。这些成员必须在派生类中实现。 <strong>(类似接口)</strong></li>
</ul>
<h1 id=""><strong>类型断言</strong></h1>
<p>TypeScript 允许你以任何方式覆盖其推断的类型。当你比编译器本身能更好地理解变量类型时，可以使用它。</p>
<pre><code class="language-typescript">const friend = {};
friend.name = 'John';  // Error! Property 'name' does not exist on type '{}'

interface Person {
  name: string;
  age: number;
}

const person = {} as Person;
person.name = 'John';  // 正确
</code></pre>
<p>最初，类型断言的语法是 <code>&lt;type&gt;</code></p>
<pre><code class="language-typescript">let person = &lt;Person&gt; {};
</code></pre>
<p>但这在 JSX 中使用时产生了歧义。因此建议使用 <code>as</code> 代替。</p>
<p>类型断言通常在从 JavaScript 迁移代码时使用，你对变量的类型了解可能比当前指派的更准确。</p>
<p>但断言也会 <strong>被认为有害。</strong></p>
<p>我们来看看上一个示例中的 Person 接口，你注意到了什么问题吗？如果你注意到丢失了 <strong><strong>age</strong></strong> 属性，恭喜，你对了！编译器可能会帮助你自动完成 Person 的属性，但如果您遗漏了任何属性，它也不会报错。</p>
<h1 id=""><strong>类型推论</strong></h1>
<p>没有明确指定出类型时，TypeScript 会推断变量类型。</p>
<pre><code class="language-typescript">/**
 * 变量声明
 */
let a = "some string";
let b = 1;
a = b;  // Error! Type 'number' is not assignable to type 'string'.

// 如果是复杂的对象，TypeScript 会用最常见的类型
// 来推断对象类型。
const arr = [0, 1, false, true];  // (number | boolean)[]
</code></pre>
<h1 id=""><strong>类型兼容性</strong></h1>
<p>类型兼容性是基于结构类型的，结构类型只使用其成员来描述类型。</p>
<p>结构化类型系统的基本规则是：如果 <code>x</code> 要兼容 <code>y</code>，那么 <code>y</code> 至少具有与 <code>x</code> 相同的属性。</p>
<pre><code class="language-typescript">interface Person {
name: string;
}

let x: Person;  // 正确，尽管不是Person接口的实现
let y = { name: 'John', age: 20 };  // type { name: string; age: number }
x = y;
</code></pre>
<p>由于 <code>y</code> 有一个成员 <code>name: string</code> 匹配 Person 接口所需的属性，这意味着 <code>x</code> 是 <code>y</code> 的子类型。因此这个赋值是合法的。</p>
<h2 id=""><em><strong>函数</strong></em></h2>
<p><strong><strong>参数数量</strong></strong><br>
在函数调用中，至少需要传入足够的参数，多余的参数不会导致任何错误。</p>
<pre><code class="language-typescript">function consoleName(person: Person) {
  console.log(person.name);
}
consoleName({ name: 'John' });           // 正确
consoleName({ name: 'John', age: 20 });  // 多余的参数也合法
</code></pre>
<p><strong><strong>返回值类型</strong></strong><br>
返回值类型必须至少包含足够的数据。</p>
<pre><code class="language-typescript">let x = () =&gt; ({name: 'John'});
let y = () =&gt; ({name: 'John', age: 20 });
x = y;  // 正确
y = x;  /* Error! Property 'age' is missing in type '{ name: string; }'
but required in type '{ name: string; age: number; }' */
</code></pre>
<h1 id=""><strong>类型保护</strong></h1>
<p>类型保护可以在条件块中缩小对象类型的范围。</p>
<h2 id="typeof"><strong>typeof</strong></h2>
<p>在条件里使用 typeof，编译器会知道变量的类型会不一致。在下面的示例中，TypeScript 会知道：在条件块之外，<code>x</code> 可能是布尔值，而布尔值上无法调用函数 <code>toFixed</code>。</p>
<pre><code class="language-typescript">function example(x: number | boolean) {
  if (typeof x === 'number') {
    return x.toFixed(2);
  }
  return x.toFixed(2); // Error! Property 'toFixed' does not exist on type 'boolean'.
}
</code></pre>
<h2 id="instanceof"><strong>instanceof</strong></h2>
<pre><code class="language-typescript">class MyResponse {
  header = 'header example';
  result = 'result example';
  // ...
}
class MyError {
  header = 'header example';
  message = 'message example';
  // ...
}
function example(x: MyResponse | MyError) {
  if (x instanceof MyResponse) {
    console.log(x.message); // Error! Property 'message' does not exist on type 'MyResponse'.
    console.log(x.result);  // 正确
  } else {
    // TypeScript 知道这里一定是 MyError
    console.log(x.message); // 正确
    console.log(x.result);  // Error! Property 'result' does not exist on type 'MyError'.
  }
}
</code></pre>
<h2 id="in"><strong>in</strong></h2>
<p><code>in</code> 运算符会检查一个属性在某对象上是否存在。</p>
<pre><code class="language-typescript">interface Person {
  name: string;
  age: number;
}
const person: Person = {
  name: 'John',
  age: 28,
};

const checkForName = 'name' in person; // true
</code></pre>
<h1 id="literaltypes"><strong>Literal Types (字面量类型)</strong></h1>
<p>字面量正是 JavaScript 原始数据类型具体的值，它们可以与 union (联合) 类型搭配使用，构造一些实用的概念。</p>
<pre><code class="language-typescript">type Orientation = 'landscape' | 'portrait';
function changeOrientation(x: Orientation) {
  // ...
}
changeOrientation('portrait'); // 正确
changeOrientation('vertical'); /* Error! Argument of type '"vertical"' is not 
assignable to parameter of type 'Orientation'. /
</code></pre>
<h2 id=""><em><strong>条件类型</strong></em></h2>
<p><em>条件类型表示类型关系的测试，并根据测试的结果选择两种可能类型中的一种。</em></p>
<pre><code class="language-typescript">type X = A extends B ? C : D;
</code></pre>
<p><em>如果 <code>A</code> 类型可以赋值给 <code>B</code> 类型，那么 <code>X</code> 是 <code>C</code> 类型；否则 <code>X</code>  是 <code>D</code> 类型。</em></p>
<h1 id=""><em><strong>泛型</strong></em></h1>
<p><em>泛型是必须包含或引用其他类型才能完成的类型。它加强了变量之间有意义的约束。</em></p>
<p><em>下面例子中的函数会返回所传入的任何类型的数组。</em></p>
<pre><code class="language-typescript">function reverse&lt;T&gt;(items: T[]): T[] {
  return items.reverse();
}
reverse([1, 2, 3]); // number[]
reverse([0, true]); // (number | boolean)[]
</code></pre>
<h2 id="keyof"><em><strong>keyof</strong></em></h2>
<p><em><code>keyof</code> 运算符会查询给定类型的键集。</em></p>
<pre><code class="language-typescript">interface Person {
  name: string;
  age: number;
}
type PersonKeys = keyof Person; // 'name' | 'age'
</code></pre>
<h2 id=""><em><strong>映射类型</strong></em></h2>
<p><em>映射类型，通过在属性类型上建立映射，从现有的类型创建新类型。具有已知类型的每个属性都会根据你指定的规则进行转换。</em></p>
<h2 id="partial"><em><strong>Partial</strong></em></h2>
<pre><code class="language-typescript">type Partial&lt;T&gt; = {
  [P in keyof T]?: T[P];
}
</code></pre>
<ul>
<li><em>泛型 Partial 类型被定义时只有一个类型参数 <code>T</code>。</em></li>
<li><em><code>keyof T</code> 表示所有 <code>T</code> 类型属性的名字（字符串字面类型）的联合。</em></li>
<li><em><code>[P in keyof T]?: T[P]</code> 表示所有 <code>T</code> 类型的属性 <code>P</code> 的类型都应该是可选的，并且都会被转换为 <code>T[P]</code>。</em></li>
<li><em><code>T[P]</code>  表示 <code>T</code> 类型的属性 <code>P</code> 的类型。</em></li>
</ul>
<h2 id="readonly"><em><strong>Readonly (只读)</strong></em></h2>
<p><em>正如在接口部分中所介绍的，TypeScript 中可以创建只读属性。 <code>Readonly</code> 类型接受一个类型 <code>T</code>，并将其所有属性设置为只读。</em></p>
<pre><code class="language-typescript">type Readonly&lt;T&gt; = {
  readonly [P in keyof T]: T[P];
};
</code></pre>
<h2 id="exclude"><em><strong>Exclude</strong></em></h2>
<p><em><code>Exclude</code> 可以从其他类型中排除某些类型。排除的是可以赋值给 <code>T</code> 的属性。</em></p>
<pre><code class="language-typescript">/**
 * type Exclude&lt;T, U&gt; = T extends U ? never : T;
 */
type User = {
  _id: number;
  name: string;
  email: string;
  created: number;
};

type UserNoMeta = Exclude&lt;keyof User, '_id' | 'created'&gt;
</code></pre>
<h2 id="pick"><strong>Pick</strong></h2>
<p><code>Pick</code> 可以从其他类型中选取某些类型。 挑选的是可以赋值给 <code>T</code> 的属性。</p>
<pre><code class="language-typescript">/**
 * type Pick&lt;T, K extends keyof T&gt; = {
 *   [P in K]: T[P];
 *  };
 */
type UserNoMeta = Pick&lt;User, 'name' | 'email'&gt;
</code></pre>
<h2 id="infer"><em><strong>infer</strong></em></h2>
<p>你可以使用 <code>infer</code> 关键字来推断条件类型的 <code>extends</code> 子句中的类型变量。这样的推断类型变量只能用于条件类型的 true 分支。</p>
<h2 id="returntype"><strong>ReturnType</strong></h2>
<p>获取函数的返回类型。</p>
<pre><code class="language-typescript">/**
 * 原版的 TypeScript's ReturnType
 * type ReturnType&lt;T extends (...args: any) =&gt; any&gt; = T extends (...args: any) =&gt; infer R ? R : any;
 */
type MyReturnType&lt;T&gt; = T extends (...args: any) =&gt; infer R ? R : any;

type TypeFromInfer = MyReturnType&lt;() =&gt; number&gt;;  // number
type TypeFromFallback = MyReturnType&lt;string&gt;;     // any
</code></pre>
<p>我们来拆解 <code>MyReturnType</code>：</p>
<ul>
<li><code>T</code> 的返回类型是 ...</li>
<li>首先，<code>T</code> 是不是一个函数？</li>
<li>如果是，那么类型解析为推断出的返回类型 <code>R</code>；</li>
<li>如果不是，类型解析为 <code>any</code>。</li>
</ul>
<h1 id=""><strong>参考资料与实用链接</strong></h1>
<p><a href="https://basarat.gitbooks.io/typescript/">https://basarat.gitbooks.io/typescript/</a></p>
<p><a href="https://www.typescriptlang.org/docs/home.html">https://www.typescriptlang.org/docs/home.html</a></p>
<p><a href="https://www.tutorialsteacher.com/typescript">https://www.tutorialsteacher.com/typescript</a></p>
<p><a href="https://github.com/dzharii/awesome-typescript">https://github.com/dzharii/awesome-typescript</a></p>
<p><a href="https://github.com/typescript-cheatsheets/react-typescript-cheatsheet">https://github.com/typescript-cheatsheets/react-typescript-cheatsheet</a></p>
<hr>
<p>为了达到学习和实践 TypeScript 的目的，我用 TS 和 React-Native（用了 hooks）构建了一个简单的 CurrencyConverter (汇率转换) 程序。你可以在 <a href="https://github.com/gustavoaz7/React-Native_Learning/tree/master/CurrencyConverter">这里</a> 查看这个项目。</p>
<p>感谢、祝贺你阅读到这里！如果你对此有任何想法，请随时发表评论。</p>
<p>你可以在 <a href="https://twitter.com/intent/follow?screen_name=gustavoaz7_">Twitter</a> 上找到我。</p>
<p>原文：<a href="https://www.freecodecamp.org/news/the-definitive-typescript-handbook/">The Definitive TypeScript Handbook</a>，作者：Gustavo Azevedo</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
