首页 >web前端 >js教程 >使用 TypeScript 构建:基于乐高的指南

使用 TypeScript 构建:基于乐高的指南

Patricia Arquette
Patricia Arquette原创
2025-01-20 23:44:13254浏览

TypeScript:从JavaScript到TypeScript的平滑过渡,就像升级你的乐高积木搭建过程!

Building with TypeScript: A Lego-Based Guide

“尽其所能,用其所有”——这是我奉行的座右铭之一。这句话也体现了成长型思维模式的一部分。我们大多数前端或JavaScript开发者,都已经开始或完全迁移到TypeScript了。但有些人可能仍然难以理解其概念,或者难以将思维方式从JavaScript转换到TypeScript的模式。为了解决这个问题,我们将使用我最喜欢的工具之一:乐高积木。让我们从这里开始:“将JavaScript想象成一套基础乐高积木,你可以自由搭建;而TypeScript则是同一套积木,但配有详细的说明书和质量控制检查。” 关于TypeScript的更深入探讨,可以参考这里、这里以及这段视频。本指南旨在展示每个JavaScript概念如何转换为TypeScript,并使用乐高类比来帮助你更容易理解这些概念。

变量作用域和提升:搭建房间

Building with TypeScript: A Lego-Based Guide

概念定义

变量作用域是指在程序中变量可访问和使用的上下文。主要有两种作用域:局部作用域全局作用域。在任何函数外部声明的变量位于全局作用域,这意味着可以在代码的任何地方访问和修改它。另一方面,在函数内部声明的变量位于局部作用域,并且只能在该函数内访问。JavaScript使用varletconst关键字来声明变量,每个关键字对作用域的影响都不同。用letconst声明的变量是块作用域的,这意味着它们只能在最近的封闭块{}内访问。相比之下,var是函数作用域的,使其在其声明的整个函数中可用。清晰地理解变量作用域有助于避免变量名称冲突和JavaScript程序中意外的副作用等问题。

提升是指在代码执行(编译阶段)之前,变量和函数声明被移动到其包含作用域顶部的行为。这意味着可以在声明变量和函数之前使用它们。函数声明是完全提升的,允许即使在代码中定义之前也能调用它们。但是,使用var声明的变量会被提升,但不会初始化其初始值,因此在赋值之前访问它们将导致undefined。用letconst声明的变量也会被提升,但不会被初始化,如果在声明之前访问它们会导致ReferenceError。理解提升有助于开发人员通过正确构造变量和函数声明来避免常见的陷阱。

乐高类比

将作用域想象成不同的乐高搭建房间:

  • 全局作用域:所有搭建者都可以访问积木的共享客厅。
  • 函数作用域:个人的搭建桌。
  • 块作用域:搭建桌的特定区域。

JavaScript 实现

<code class="language-javascript">// 全局搭建房间
const globalBricks = "每个人都可以使用这些";
function buildSection() {
    // 个人搭建桌
    var tableBricks = "仅供此搭建者使用";

    if (true) {
        // 特定区域
        let sectionBricks = "仅供此部分使用";
    }
}</code>

TypeScript 演变

<code class="language-typescript">// 为我们的搭建房间添加类型安全
type BrickType = "regular" | "special" | "rare";
const globalBricks: BrickType = "regular";

function buildSection(): void {
    // TypeScript确保我们只使用有效的积木类型
    const tableBricks: BrickType = "special";

    if (true) {
        // TypeScript阻止在此块之外使用sectionBricks
        let sectionBricks: BrickType = "rare";
    }
}

// 真实世界的例子:配置管理
interface AppConfig {
    readonly apiKey: string;
    environment: "dev" | "prod";
    features: Set<string>;
}

const config: AppConfig = {
    apiKey: "secret",
    environment: "dev",
    features: new Set(["feature1", "feature2"])
};</code>

函数和闭包:搭建说明书

Building with TypeScript: A Lego-Based Guide

概念定义

函数是旨在执行特定任务的可重用代码块。这增强了模块化和代码效率。它们可以使用function关键字定义,后跟名称、括号()和用大括号{}括起来的代码块。参数可以在括号或大括号内传递到函数中,这些参数充当调用函数时提供的值的占位符。JavaScript还支持匿名函数(没有名称)和箭头函数(提供更简洁的语法)。函数可以使用return语句返回值,或者执行不返回值的操作。此外,JavaScript中的函数是一等对象,这意味着它们可以赋值给变量、作为参数传递以及从其他函数返回,从而实现函数式编程模式。

闭包是一个强大的特性,它允许函数记住并访问其词法作用域,即使函数在该作用域之外执行也是如此。当在一个函数内部定义一个函数并引用外部函数中的变量时,可以创建闭包。即使外部函数执行完毕后,内部函数仍然可以访问这些变量。此功能对于数据封装和在事件处理程序或回调等环境中维护状态非常有用。闭包支持私有变量等模式,其中函数可以公开特定行为,同时隐藏实现细节。

乐高类比

  • 函数就像搭建说明书。
  • 参数就像所需的积木。
  • 返回值就像已完成的结构。
  • 闭包就像密封的搭建套件,其中包含一些永久包含的积木。

JavaScript 实现

<code class="language-javascript">function buildHouse(floors, color) {
    const foundation = "concrete";

    return function addRoof(roofStyle) {
        return `${color} house with ${floors} floors and ${roofStyle} roof on ${foundation}`;
    };
}</code>

TypeScript 演变

<code class="language-typescript">// 带有类型的基本函数
interface House {
    floors: number;
    color: string;
    roofStyle: string;
    foundation: string;
}

// 为我们的搭建者添加类型安全
function buildHouse(
    floors: number,
    color: string
): (roofStyle: string) => House {
    const foundation = "concrete";

    return (roofStyle: string): House => ({
        floors,
        color,
        roofStyle,
        foundation
    });
}

// 真实世界的例子:组件工厂
interface ComponentProps {
    id: string;
    style?: React.CSSProperties;
    children?: React.ReactNode;
}

function createComponent<T extends ComponentProps>(
    baseProps: T
): (additionalProps: Partial<T>) => React.FC<T> {
    return (additionalProps) => {
        // 组件实现
        return (props) => <div></div>;
    };
}</code>

对象和原型:搭建技巧

Building with TypeScript: A Lego-Based Guide

概念定义

JavaScript中的对象是基本的数据结构,用作相关数据和功能的容器。它们由键值对组成,其中每个键(属性)都映射到一个值,该值可以是任何有效的JavaScript类型,包括函数(方法)。对象可以通过几种方式创建:

  • 对象字面量:const obj = {}
  • 构造函数:new Object()
  • Object.create()方法

原型系统是JavaScript内置的继承机制。每个对象都与另一个对象(称为其原型)具有内部链接。当尝试访问对象上不存在的属性时,JavaScript会自动在其原型链中查找它。此对象链会一直持续到到达具有null原型的对象,通常是Object.prototype。理解原型对于以下方面至关重要:

  • 实现继承
  • 在实例之间共享方法
  • 管理内存效率
  • 建立对象层次结构

乐高类比

将对象和原型想象成这样:

  • 对象就像带有自己独特积木和说明书的专用乐高套件。
  • 原型就像多个套件可以参考的主模板。
  • 继承就像拥有一个基本套件,更高级的套件可以以此为基础搭建。
  • 属性就像每个套件中的特定积木。
  • 方法就像每个套件中包含的特殊搭建技巧。

JavaScript 实现

<code class="language-javascript">// 全局搭建房间
const globalBricks = "每个人都可以使用这些";
function buildSection() {
    // 个人搭建桌
    var tableBricks = "仅供此搭建者使用";

    if (true) {
        // 特定区域
        let sectionBricks = "仅供此部分使用";
    }
}</code>

TypeScript 演变

<code class="language-typescript">// 为我们的搭建房间添加类型安全
type BrickType = "regular" | "special" | "rare";
const globalBricks: BrickType = "regular";

function buildSection(): void {
    // TypeScript确保我们只使用有效的积木类型
    const tableBricks: BrickType = "special";

    if (true) {
        // TypeScript阻止在此块之外使用sectionBricks
        let sectionBricks: BrickType = "rare";
    }
}

// 真实世界的例子:配置管理
interface AppConfig {
    readonly apiKey: string;
    environment: "dev" | "prod";
    features: Set<string>;
}

const config: AppConfig = {
    apiKey: "secret",
    environment: "dev",
    features: new Set(["feature1", "feature2"])
};</code>

异步编程:搭建团队

Building with TypeScript: A Lego-Based Guide

概念定义

异步函数和编程

异步函数是JavaScript中一种特殊的函数类型,它提供了一种优雅的方式来处理异步操作。当用async关键字声明时,这些函数会自动返回一个Promise,并在其主体中启用await关键字的使用。await运算符会暂停函数的执行,直到Promise被解决或拒绝,从而允许以更同步、更易读的风格编写异步代码。此语法有效地减少了回调的复杂性,并消除了对嵌套Promise链的需求。例如,在async function fetchData() { const response = await fetch(url); }中,函数会在继续执行之前等待fetch操作完成,使代码的行为更可预测,同时确保主线程保持不被阻塞。当处理相互依赖的多个异步操作时,此模式特别有用,因为它允许开发人员编写清楚地表达操作顺序的代码,而不会牺牲性能。

Promise

Promise表示一个可能现在可用、将来可用或永远不可用的值。它是一个具有三种可能状态的对象:等待中、已完成或已拒绝。它用于处理异步操作。Promise具有诸如.then().catch().finally()等方法,用于根据结果链接操作。这使得它们成为嵌套回调的有力替代方案,提高了代码的可读性和错误处理能力。

乐高类比

  • 异步函数就像团队成员在处理不同的部分。
  • Promise就像交付已完成部分的协议。

JavaScript 实现

<code class="language-javascript">// 全局搭建房间
const globalBricks = "每个人都可以使用这些";
function buildSection() {
    // 个人搭建桌
    var tableBricks = "仅供此搭建者使用";

    if (true) {
        // 特定区域
        let sectionBricks = "仅供此部分使用";
    }
}</code>

TypeScript 演变

<code class="language-typescript">// 为我们的搭建房间添加类型安全
type BrickType = "regular" | "special" | "rare";
const globalBricks: BrickType = "regular";

function buildSection(): void {
    // TypeScript确保我们只使用有效的积木类型
    const tableBricks: BrickType = "special";

    if (true) {
        // TypeScript阻止在此块之外使用sectionBricks
        let sectionBricks: BrickType = "rare";
    }
}

// 真实世界的例子:配置管理
interface AppConfig {
    readonly apiKey: string;
    environment: "dev" | "prod";
    features: Set<string>;
}

const config: AppConfig = {
    apiKey: "secret",
    environment: "dev",
    features: new Set(["feature1", "feature2"])
};</code>

现代特性:高级搭建技巧

Building with TypeScript: A Lego-Based Guide

概念定义

解构

这是一种将数组中的值或对象中的属性提取到不同的变量中的简洁方法。数组解构使用方括号[],而对象解构使用大括号{}。此语法通过将值直接解包到变量中,减少了对重复代码的需求,从而更容易处理复杂的数据结构。例如,const [a, b] = [1, 2]将1赋值给a,将2赋值给b,而const { name } = person从person对象中提取name属性。

展开运算符

展开运算符由三个点(...)表示。它允许将诸如数组或对象之类的可迭代对象扩展到需要多个元素或键值对的地方。它可以用于复制、组合或将数组元素作为函数参数传递。例如,const arr = [1, 2, ...anotherArray]

可选链

可选链由?.表示。它提供了一种安全的方式来访问深度嵌套的对象属性,而不会在属性未定义或为null时导致错误。如果引用为nullish,它会短路并立即返回undefined。例如,user?.address?.street在访问street之前检查user和address是否存在。此语法可防止运行时错误,并使处理嵌套数据结构更加简洁和不易出错,尤其是在API或依赖于用户输入的数据中。

乐高类比

  • 解构就像将积木分类到容器中。
  • 展开运算符就像在套件之间复制积木。
  • 可选链就像在使用积木之前检查积木是否存在。

JavaScript 实现

<code class="language-javascript">function buildHouse(floors, color) {
    const foundation = "concrete";

    return function addRoof(roofStyle) {
        return `${color} house with ${floors} floors and ${roofStyle} roof on ${foundation}`;
    };
}</code>

TypeScript 演变

<code class="language-typescript">// 带有类型的基本函数
interface House {
    floors: number;
    color: string;
    roofStyle: string;
    foundation: string;
}

// 为我们的搭建者添加类型安全
function buildHouse(
    floors: number,
    color: string
): (roofStyle: string) => House {
    const foundation = "concrete";

    return (roofStyle: string): House => ({
        floors,
        color,
        roofStyle,
        foundation
    });
}

// 真实世界的例子:组件工厂
interface ComponentProps {
    id: string;
    style?: React.CSSProperties;
    children?: React.ReactNode;
}

function createComponent<T extends ComponentProps>(
    baseProps: T
): (additionalProps: Partial<T>) => React.FC<T> {
    return (additionalProps) => {
        // 组件实现
        return (props) => <div></div>;
    };
}</code>

总结

Building with TypeScript: A Lego-Based Guide

从JavaScript到TypeScript的过渡就像升级你的乐高搭建过程:

  1. JavaScript(基础搭建):

    • 自由形式的搭建
    • 灵活的积木使用
    • 运行时错误发现
  2. TypeScript(专业搭建):

    • 详细和具体的说明书
    • 积木兼容性检查
    • 建造前的错误预防

关键过渡技巧:

  1. 从基本类型注解开始。
  2. 逐渐添加接口和类型定义。
  3. 使用编译器尽早捕获错误。
  4. 尽可能利用类型推断。
  5. 逐渐添加严格的null检查和其他编译器选项。

记住:TypeScript是在你的JavaScript知识的基础上构建的,它增加了安全性和清晰度,而不是改变基本的搭建过程。也就是说,我的建议仍然是……先学习JavaScript,然后再学习TypeScript。

参考文献

Building with TypeScript: A Lego-Based Guide

以上是使用 TypeScript 构建:基于乐高的指南的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn