74道TypeScript高频题整理(附答案背诵版)

1.简述什么是TypeScript ?

TypeScript是一种由Microsoft开发和维护的开源编程语言。它是JavaScript的一个超集,意味着它扩展了JavaScript的功能,包括添加了类型系统和对ES6+的新特性的支持。TypeScript的设计目标是帮助开发者捕捉代码中的错误,通过在编译阶段进行类型检查来实现这一点。这可以提高代码的质量和可维护性,特别是在开发大型的或者是多人协作的项目时。

TypeScript的核心优势之一是它的可选静态类型系统。开发者可以为变量、函数的参数、返回值等声明类型,但这并不是强制的。这意味着你可以逐步地将一个JavaScript项目迁移到TypeScript,而不需要一开始就重写所有东西。此外,TypeScript的类型系统是非常强大和灵活的,支持包括基础类型(如字符串、数字和布尔值)、枚举、接口、类、数组、元组以及联合类型和交叉类型等高级类型。

下面是一个简单的TypeScript示例,展示了如何声明变量的类型:

let isCompleted: boolean = false; // 声明一个布尔类型的变量

function greet(name: string): void {
    console.log("Hello, " + name + "!");
}

greet("Alice"); // 正确
greet(42); // 错误,TypeScript编译时会报错,因为42不是一个字符串

在这个例子中,我们定义了一个布尔类型的变量isCompleted和一个接受字符串参数的函数greet。如果尝试用非字符串类型的参数调用greet函数,TypeScript编译器将会提示类型错误。这就是TypeScript如何帮助开发者在代码运行之前就捕捉到潜在的错误。

2.简述TypeScript 的主要特点是什么?

TypeScript的主要特点可以总结如下:

  1. 可选的静态类型系统:TypeScript的核心特性之一是它的静态类型系统,这对于捕捉常见的编程错误非常有帮助。类型是可选的,意味着你可以决定是否为变量、函数参数等指定类型。这使得从JavaScript过渡到TypeScript更加容易和灵活。

  2. 类型推断:即使你不显式声明类型,TypeScript也能根据上下文自动推断出变量或表达式的类型。这减少了需要显式声明类型的情况,同时仍然提供了类型安全的好处。

  3. 支持最新的JavaScript特性:TypeScript支持ECMAScript标准的最新特性,这意味着你可以使用最新的JavaScript语法和特性编写代码,然后TypeScript编译器会将其转换成兼容旧版本JavaScript引擎的代码。

  4. 跨平台和跨浏览器兼容性:通过将TypeScript代码编译为普通的JavaScript,生成的代码可以在任何支持JavaScript的平台上运行,无论是浏览器还是Node.js环境。

  5. 强大的工具支持:TypeScript提供了强大的开发工具支持,包括自动完成、类型检查和重构等功能,这些都能在开发过程中提高生产力和代码质量。这些工具支持在流行的IDE和编辑器中都有很好的集成,如Visual Studio Code。

  6. 易于集成:你可以逐渐将TypeScript集成到现有的JavaScript项目中,而不是一开始就全面转换。这是因为TypeScript是JavaScript的超集,所以现有的JavaScript代码可以直接在TypeScript项目中使用。

  7. 丰富的社区和生态系统:由于Microsoft和许多其他组织和开发者的积极参与,TypeScript拥有一个非常活跃的社区和丰富的生态系统。这意味着有大量的类型定义、工具和库可供使用,能够帮助你快速开发应用。

举个例子,如果你正在使用一个流行的JavaScript库,很可能已经有人为该库编写了TypeScript的类型定义文件(.d.ts文件),这样你就可以在TypeScript项目中享受到自动完成和类型检查等特性,而不需要自己从头写类型声明。

3.简述TypeScript 有什么好处?

TypeScript为开发者提供了多种好处,尤其是在构建大型或复杂的JavaScript应用时。以下是TypeScript的一些主要优点:

  1. 静态类型检查:TypeScript的最显著特点是它的静态类型系统。通过在开发阶段引入类型检查,TypeScript帮助开发者发现并修正错误,这些错误在纯JavaScript项目中可能直到运行时才会暴露。静态类型检查可以提升代码质量,减少潜在的运行时错误。

  2. 代码自动补全和智能感知:类型系统不仅帮助捕获错误,还能提高开发效率。大多数现代IDE和代码编辑器可以利用TypeScript提供的类型信息,提供更好的代码自动完成、函数签名提示等智能感知功能。

  3. 更好的重构支持:类型信息使得重构代码更加安全和容易。当你重命名一个类或函数时,TypeScript可以帮助确保项目中所有的引用都被更新,减少了手动查找和替换引起的错误。

  4. 允许使用最新的JavaScript特性:TypeScript支持最新的ECMAScript标准,允许你使用最新的JavaScript特性,比如async/await、箭头函数等。TypeScript编译器会将这些现代特性转换成向下兼容的JavaScript代码,确保你的应用可以在老旧的浏览器上运行。

  5. 适合大型项目:随着JavaScript项目的增长,维护和管理其复杂性变得更加困难。TypeScript的类型系统和编译时检查使得开发大型应用更加可管理和可维护。

  6. 社区支持和生态系统:TypeScript拥有一个活跃的社区和丰富的生态系统。许多流行的JavaScript库和框架都提供了TypeScript的类型定义,使得它们能够无缝集成到TypeScript项目中。

  7. 渐进式迁移:你可以逐步将现有的JavaScript项目迁移到TypeScript,这为项目提供了灵活性。TypeScript允许你一次迁移一个文件,同时保持项目的其余部分为纯JavaScript。

总的来说,TypeScript提供的静态类型检查、工具支持和对最新JavaScript特性的支持,使得开发大型和复杂的应用变得更加高效和可靠。这些好处使得TypeScript成为许多企业和开发者构建应用程序时的首选语言。

4.TypeScript 的内置数据类型有哪些?

TypeScript提供了多种内置数据类型,以帮助开发者定义变量的类型,这些类型包括:

  1. Boolean:布尔值类型,用于表示逻辑上的真(true)或假(false)。

    let isDone: boolean = false;
    
  2. Number:数字类型,所有的数字,包括整数和浮点数,都用Number类型表示,支持十进制、十六进制、二进制和八进制字面量。

    let decimal: number = 6;
    let hex: number = 0xf00d;
    let binary: number = 0b1010;
    let octal: number = 0o744;
    
  3. String:字符串类型,用于表示文本数据。可以使用双引号(" ")、单引号(' ')或者模板字符串(``)来定义字符串值。

    let color: string = "blue";
    color = 'red';
    let fullName: string = `Bob Bobbington`;
    
  4. Array:数组类型,可以在元素类型后面使用[]来表示变量是该类型的数组,或者使用泛型数组类型Array<元素类型>

    let list: number[] = [1, 2, 3];
    let listGeneric: Array<number> = [1, 2, 3];
    
  5. Tuple:元组类型,允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。

    let x: [string, number];
    x = ["hello", 10]; // 正确
    
  6. Enum:枚举类型,用于定义一组命名的常数。TypeScript的枚举可以是数字或字符串枚举。

    enum Color {Red, Green, Blue}
    let c: Color = Color.Green;
    
  7. Any:任意类型,允许赋值为任意类型的值,是一种逃避类型检查的方法。

    let notSure: any = 4;
    notSure = "maybe a string instead";
    
  8. Void:用于标识没有任何类型,通常用在没有返回值的函数的返回类型上。

    function warnUser(): void {
        console.log("This is my warning message");
    }
    
  9. Null 和 Undefined:TypeScript里,nullundefined有各自的类型名为nullundefined。默认情况下,它们是所有类型的子类型,就是说你可以将nullundefined赋值给比如number类型的变量。

    let u: undefined = undefined;
    let n: null = null;
    
  10. Never:表示那些永不存在的值的类型,例如,never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回类型。

    function error(message: string): never {
        throw new Error(message);
    }
    
  11. Object:表示非原始类型,即除numberstringbooleansymbolnullundefined之外的类型。

    declare function create(o: object | null): void;
    

这些基本数据类型能够帮助你在TypeScript中构建和管理复杂的数据结构,提高应用的可靠性和维护性。

5.简述TypeScript 目前的稳定版本 ?

TypeScript的最新稳定版本是4.7。然而,TypeScript的开发团队经常发布新版本,每个新版本都会带来新的特性、改进和错误修复。为了获取最新的稳定版本信息,建议访问TypeScript的官方网站或其GitHub页面。

如果你需要实时的版本信息,可以通过运行npm命令npm show typescript version在命令行中查看TypeScript的最新稳定版本。此外,你也可以通过访问TypeScript的npm包页面或GitHub仓库来获取最新的版本信息和更新日志。

6.简述TypeScript 中的接口 ?

TypeScript中的接口(Interfaces)是一个非常强大的特性,用于定义对象的形状(shape),即对象中应该包含哪些属性和方法以及它们的类型。接口在TypeScript中主要用于静态类型检查,帮助开发者在编译时期捕获错误,而不是在运行时。

接口定义了一套契约,对象可以实现(implement)一个或多个接口,类可以通过接口来定义自己的公共API。接口只存在于TypeScript的类型检查阶段,并不编译成JavaScript代码。

基本用法

在最简单的形式中,接口可以用来描述一个对象需要有哪些属性和属性的类型:

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

let john: Person = { name: "John Doe", age: 30 };

在这个例子中,Person接口定义了一个对象,这个对象有两个属性:nameage,分别是字符串和数字类型。任何赋值给john变量的对象都必须符合Person接口的形状。

可选属性

接口的属性不必全部是必须的,你可以通过在属性名后加上?标记来指定属性为可选:

interface Person {
    name: string;
    age?: number; // 可选属性
}

let jane: Person = { name: "Jane Doe" }; // 正确,age是可选的
方法

接口同样可以描述对象中的方法:

interface Greeter {
    greet(): void;
}

class EnglishGreeter implements Greeter {
    greet() {
        console.log("Hello!");
    }
}

在这个例子中,Greeter接口定义了一个greet方法,EnglishGreeter类通过实现这个接口,承诺提供一个greet方法的实现。

接口继承

接口还可以继承一个或多个其他接口,这使得我们可以从其他接口复制成员到当前接口,创建出复杂的类型:

interface Named {
    name: string;
}

interface Logged {
    log(name: string): void;
}

interface Person extends Named, Logged {
    age: number;
}

在这个例子中,Person接口继承了NamedLogged接口,因此任何Person类型的对象都需要符合这三个接口定义的形状。

动态属性

接口还可以用来定义具有某种模式的对象,其中对象的属性名是动态的:

interface StringArray {
    [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

这个StringArray接口表明,当使用数字索引去获取StringArray的时候,会得到一个字符串类型的返回值。

通过这些特性,TypeScript的接口为构建健壮的类型系统和促进代码的可读性和维护性提供了强大的工具。

7.简述TypeScript 中的模块是什么?

在TypeScript中,模块是一个强大的方式来组织和封装代码。模块在其自身的作用域内执行,而不是在全局作用域内,这意味着在模块内部声明的变量、函数、类等不会自动成为全局作用域的一部分。这有助于避免全局命名空间的污染,并确保模块的代码可以被重用和维护。

模块的一个关键特性是它们可以导入其他模块导出的功能,也可以导出自己的功能供其他模块使用。这使得开发者可以创建依赖于其他模块的功能的应用程序,同时也可以提供可被其他模块重用的功能。

导出(Export)

在TypeScript模块中,任何声明(比如变量、函数、类、类型别名或接口)都默认是私有的,如果你想在其他模块中访问它们,你需要使用export关键字将它们标记为公开的。

// someModule.ts
export interface SomeInterface {
    // ...
}

export class SomeClass {
    // ...
}

export const someVariable = "someValue";
导入(Import)

如果你想在一个模块中使用另一个模块导出的功能,你需要使用import语句。

// otherModule.ts
import { SomeClass, someVariable } from "./someModule";

const instance = new SomeClass();
console.log(someVariable);
默认导出(Default Export)

每个模块可以有一个default导出,这通常用于当模块只导出一个主要的东西时。

// defaultExportModule.ts
export default class DefaultClass {
    // ...
}

然后可以这样导入:

import DefaultClass from "./defaultExportModule";
模块解析

TypeScript解析模块时,会尝试根据导入语句找到相应的.ts.tsx.d.ts文件。如果没有找到,它会尝试加载一个外部模块。模块解析策略可以在tsconfig.json文件中配置,常见的策略有"Node"和"Classic"。

总结

TypeScript中的模块提供了代码封装和重用的强大机制。通过使用模块,开发者可以创建清晰、维护性强的代码基础,这对于开发大型应用程序尤其重要。模块使得管理依赖、声明和使用类型以及组织代码变得更加简单和直观。

8.描述后端如何使用TypeScript?

TypeScript不仅可以在前端开发中使用,也非常适合于后端开发。它可以帮助开发者构建更加健壮、易于维护的后端应用程序。使用TypeScript进行后端开发通常涉及以下几个方面:

1. 使用Node.js和TypeScript

Node.js是一个流行的JavaScript运行时,使得可以在服务器端执行JavaScript代码。由于TypeScript最终会被编译成JavaScript,这意味着你可以使用TypeScript编写Node.js应用程序。这样做的好处是你可以利用TypeScript的类型系统来提高代码的质量和可维护性。

为了在Node.js项目中使用TypeScript,你需要:

  • 安装TypeScript:通过npm(Node包管理器)安装TypeScript。

    npm install -D typescript
    
  • 配置TypeScript:使用tsc --init命令创建一个tsconfig.json文件,该文件包含TypeScript编译器的配置选项。

  • 编写TypeScript代码:你可以在项目中开始编写TypeScript代码了。通常,你会将源代码放在一个特定的目录中,如src

  • 编译TypeScript代码:使用TypeScript编译器(tsc)编译代码,生成JavaScript代码。

    tsc
    
  • 运行编译后的JavaScript代码:使用Node.js运行编译后的JavaScript代码。

    node dist/app.js
    
2. 使用TypeScript与后端框架

有许多Node.js后端框架支持或易于与TypeScript集成,比如Express、NestJS、Koa等。这些框架提供了路由、中间件、控制器等概念,使得开发RESTful API和其他服务器端逻辑变得简单。

  • Express:虽然Express本身是用JavaScript编写的,但你可以使用@types/express包来获得Express的TypeScript类型定义,这使得在TypeScript项目中使用Express变得简单。
  • NestJS:NestJS是一个用TypeScript编写的框架,它提供了一个用于构建高效、可维护的服务器端应用程序的强大架构。NestJS天生支持TypeScript,是开箱即用的。
3. 类型安全的数据库交互

在后端开发中,与数据库的交互是常见需求。使用TypeScript,你可以利用ORM(对象关系映射)工具,如TypeORM、Prisma等,这些工具提供了类型安全的方式来执行数据库操作。这意味着你可以在编译时捕获与数据库交互相关的错误,而不是在运行时。

4. 利用类型系统进行更好的协作和维护

在大型项目或团队项目中,TypeScript的类型系统可以帮助开发者更好地理解和使用代码,减少沟通成本,提高开发效率。类型注解和接口可以作为文档,帮助新团队成员快速理解项目结构和业务逻辑。

总结

通过上述方法,TypeScript可以有效地用于后端开发,提高代码质量、增强开发体验、加速开发流程,并最终构建出更加健壮、可维护的后端应用程序。

9.简述TypeScript 中的类型断言 ?

在TypeScript中,类型断言是一种方式,允许开发者告诉编译器他们知道某个值的具体类型。类型断言像是一种方式,可以绕过TypeScript的类型检查系统,在你比TypeScript更了解某个值的类型时使用。它不会重新结构数据或改变数据的类型,而是在编译时期对类型检查器作出指示。

类型断言有两种语法形式:

  1. 尖括号语法
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
  1. as语法
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

两种形式是等价的,但在使用JSX的TypeScript代码中,只允许使用as语法,因为尖括号语法与JSX的标签语法冲突。

使用场景

类型断言常用于以下几种场景:

  • 当你比TypeScript更确切地知道一个值的类型时。例如,当你从一个泛型集合中取出值时,你可能知道该值的具体类型,而TypeScript默认无法知道。
  • 当你处理混合类型的数据时,可能需要根据不同的情况将数据断言为合适的类型。
  • 在与旧JavaScript代码交互时,特别是当使用any类型的对象时,类型断言可以帮助恢复类型信息,以便在TypeScript代码中利用类型检查。
注意事项

尽管类型断言很有用,但它应该谨慎使用,因为滥用类型断言可能会导致运行时错误。由于类型断言告诉编译器“相信我,我知道我在做什么”,它会绕过TypeScript的类型检查。如果你的断言错误,那么TypeScript编译器不会报错,但在运行时可能会因为类型不匹配而出现问题。因此,在使用类型断言时,确保你对被断言的值的类型非常确信。

10.如何在 TypeScript 中创建变量

在TypeScript中创建变量的方式非常类似于JavaScript,但你可以(并且通常应该)提供一个类型注解来明确变量的类型。类型注解是TypeScript特有的,它允许你定义变量、参数和函数返回值的类型。这不仅有助于编译器理解你的代码意图,还提供了代码编辑器的自动完成和类型检查功能。

基本变量声明

使用letconst关键字可以创建变量和常量,就像在现代JavaScript(ES6及之后版本)中一样。let用于声明可以重新赋值的变量,而const用于声明一个只读常量,一旦赋值后不能再改变。

声明一个简单的变量:
let isDone: boolean = false;

这里,isDone是一个布尔类型的变量,初始值为false

声明一个常量:
const maxNumber: number = 100;

这里,maxNumber是一个数值类型的常量,值为100

类型推断

TypeScript具有类型推断能力,这意味着即使你不显式提供类型注解,TypeScript也能够根据你的代码自动推断出变量的类型。因此,如果你在声明变量时直接初始化它,TypeScript可以推断出变量的类型。

let isDone = false; // 类型被推断为boolean
const maxNumber = 100; // 类型被推断为number

在这些例子中,尽管没有显式指定类型,TypeScript也能推断isDoneboolean类型,maxNumbernumber类型。

使用类型注解

当TypeScript无法自动推断变量类型,或者你想确保变量只能被赋予特定类型的值时,应该使用类型注解。

let message: string;
message = "Hello, TypeScript!";

在这个例子中,message变量被显式地注解为string类型。这意味着尝试将非字符串值赋给message将会导致编译错误。

动态类型(any类型)

如果你不希望对变量的类型进行限制,可以使用any类型,这告诉TypeScript跳过该变量的类型检查。

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean

使用any类型可以让变量接受任何类型的值,但这样做会失去TypeScript类型安全的优势。因此,除非真的需要,否则尽量避免使用any类型。

总结

在TypeScript中创建变量时提供类型注解是一个好习惯,它可以帮助你利用TypeScript的强大类型系统来编写更清晰、更可维护的代码。然而,根据具体情况,TypeScript的类型推断也可以减少需要显式声明的类型数量,使代码保持简洁。

11.简述如何TypeScript中如何从子类调用基类构造函数?

在TypeScript中,从子类调用基类的构造函数是通过super关键字实现的。当你在子类中定义一个构造函数时,你必须首先调用super(),这会执行基类的构造函数。在调用super()之后,你可以在子类构造函数中执行其他初始化操作。

这是面向对象编程中的一个常见模式,用于确保继承的类正确地初始化了其基类部分。

示例

假设我们有一个基类Person,它有一个构造函数,该构造函数接受name作为参数:

class Person {
    name: string;

    constructor(name: string) {
        this.name = name;
    }
}

现在,我们创建一个Employee类,它继承自Person。我们希望Employee类接受一个额外的参数employeeID,但同时也需要从Person类继承name属性。这就是我们如何做到的:

class Employee extends Person {
    employeeID: number;

    constructor(name: string, employeeID: number) {
        super(name); // 调用基类(Person)的构造函数
        this.employeeID = employeeID;
    }
}

在这个例子中,Employee类的构造函数首先通过super(name)调用了Person类的构造函数,传递了name参数。这确保了Employee实例的name属性被正确初始化。之后,Employee类的构造函数继续设置employeeID属性。

注意事项
  • 当你在子类中定义构造函数时,调用super()是必需的,即使基类没有定义构造函数。如果基类没有显式定义构造函数,它会有一个默认的空构造函数,你仍然需要在子类构造函数中调用super()
  • super()调用必须是子类构造函数中的第一条语句。这是因为在基类的构造函数执行完成之前,子类的实例尚未被初始化,所以你不能在调用super()之前访问this

通过这种方式,TypeScript(和ES6的类)支持基于类的面向对象编程中的继承和构造函数调用,允许开发者构建复杂的类层次结构。

12.解释如何使用 TypeScript mixin?

在TypeScript中,mixin提供了一种灵活的方式来复用类的成员,而无需使用传统的继承。一个mixin是一个类,它提供了可以被其他类使用而不需要继承的方法和属性。使用mixin的主要目的是促进代码的复用。

要在TypeScript中实现mixin,你需要遵循几个步骤来组合一个或多个现有类的行为到一个新的类中。这里是一个基本的过程:

1. 定义Mixin

首先,你需要定义一个或多个mixin。Mixin通常作为一个实现了某些功能但不会被单独使用的类。

class DisposableMixin {
    isDisposed: boolean;
    dispose() {
        this.isDisposed = true;
    }
}

class ActivatableMixin {
    isActive: boolean;
    activate() {
        this.isActive = true;
    }
    deactivate() {
        this.isActive = false;
    }
}
2. 应用Mixin

接下来,你需要一个助手函数,它将mixin的成员复制到目标类中。

function applyMixins(derivedCtor: any, baseCtors: any[]) {
    baseCtors.forEach(baseCtor => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
            derivedCtor.prototype[name] = baseCtor.prototype[name];
        });
    });
}
3. 创建一个类,使用Mixin

现在,你可以创建一个新的类,并使用applyMixins函数将一个或多个mixin应用到这个新类中。

class SmartObject implements DisposableMixin, ActivatableMixin {
    constructor() {
        setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500);
    }

    interact() {
        this.activate();
    }

    // Mixin properties
    isDisposed: boolean = false;
    dispose: () => void;
    isActive: boolean = false;
    activate: () => void;
    deactivate: () => void;
}

applyMixins(SmartObject, [DisposableMixin, ActivatableMixin]);

在这个例子中,SmartObject类通过applyMixins函数,获得了DisposableMixinActivatableMixin的方法和属性。注意,在SmartObject类中,我们需要为mixin中的所有方法和属性声明类型,以确保类型安全。

使用Mixin的好处和限制

使用mixin可以让你把不同类的功能组合到一个类中,而不需要通过继承来建立一个复杂的类层次结构。这使得代码更加灵活和可重用。然而,过度使用mixin可能会使代码变得难以理解和维护,特别是当有多个mixin相互作用时。因此,应该谨慎使用mixin,确保它们不会使类的设计变得过于复杂。

Mixin是TypeScript提供的一种高级技术,允许开发者以灵活和可重用的方式来组合和重用代码。正确使用mixin可以在保持代码清晰和简洁的同时,增加代码的复用性和灵活性。

13.TypeScript 中如何检查 null 和 undefined?

在TypeScript中,nullundefined有各自的类型分别是nullundefined。检查变量是否为nullundefined是常见的需求,尤其是在处理外部数据或复杂的逻辑时。TypeScript提供了几种方式来检查nullundefined

严格的空检查(Strict Null Checks)

在TypeScript中启用严格的空检查(通过tsconfig.json中的"strictNullChecks": true选项)是处理nullundefined的首选方法。启用该选项后,TypeScript会将nullundefined视为其它类型(如stringnumber等)的有效值,这迫使你在使用可能为nullundefined的变量之前显式地检查它们。

使用类型保护进行检查

你可以使用简单的if语句来检查一个值是否为nullundefined,这在TypeScript中被称为类型保护:

function doSomething(x: string | null) {
    if (x === null) {
        // x is null here
        console.log("x is null");
    } else {
        // x is string here
        console.log(x.toUpperCase()); // OK
    }
}

同样,对于undefined的检查:

function doSomethingElse(x: string | undefined) {
    if (x === undefined) {
        // x is undefined here
        console.log("x is undefined");
    } else {
        // x is string here
        console.log(x.toUpperCase()); // OK
    }
}
使用非空断言操作符

如果你确定一个值不会是nullundefined,但类型系统不这么认为,你可以使用非空断言操作符!来告诉TypeScript该值一定不为nullundefined

function doAnotherThing(x: string | null) {
    console.log(x!.toUpperCase()); // 使用 ! 断言x不为null
}

请注意,过度使用非空断言操作符可能会隐藏潜在的问题,应当谨慎使用。

可选链(Optional Chaining)

TypeScript 3.7引入了可选链(?.),它允许你安全地访问深层嵌套的属性,而不必显式检查每一级是否为nullundefined

type User = {
    info?: {
        name?: string;
    };
};

const user: User = {};

const name = user.info?.name; // 如果user.info是undefined,则name也是undefined,而不是抛出错误
空值合并操作符

空值合并操作符(??)允许你为nullundefined的值提供一个默认值:

const name = user.info?.name ?? "default name";

在这个例子中,如果user.info?.name的结果是nullundefined,则name将被赋值为"default name"

这些工具和技巧可以帮助你在TypeScript中更安全、更有效地处理nullundefined

14.TypeScript 中的 getter/setter 是什么?你如何使用它们?

在TypeScript中,getter和setter是类属性访问的特殊方法,允许你对类成员的读取和赋值进行更细致的控制。通过使用getter和setter,你可以在属性被访问或修改时执行额外的逻辑,比如验证数据、执行计算、触发事件等。

Getter

一个getter方法允许你定义一个“虚拟”属性,当这个属性被访问时,实际上执行的是一个方法。你可以使用get关键字来定义一个getter。

Setter

类似地,一个setter方法允许你定义当属性被赋值时执行的操作。你可以使用set关键字来定义一个setter。

使用Getter和Setter

下面是一个使用getter和setter的例子,假设我们有一个Person类,我们想要控制对firstNamelastName属性的访问,同时提供一个“虚拟”属性fullName

class Person {
    private _firstName: string;
    private _lastName: string;

    constructor(firstName: string, lastName: string) {
        this._firstName = firstName;
        this._lastName = lastName;
    }

    get firstName(): string {
        return this._firstName;
    }

    set firstName(value: string) {
        this._firstName = value;
    }

    get lastName(): string {
        return this._lastName;
    }

    set lastName(value: string) {
        this._lastName = value;
    }

    get fullName(): string {
        return `${this._firstName} ${this._lastName}`;
    }

    set fullName(name: string) {
        const parts = name.split(' ');
        this._firstName = parts[0];
        this._lastName = parts[1];
    }
}

const person = new Person("John", "Doe");
console.log(person.fullName); // John Doe

person.fullName = "Jane Doe";
console.log(person.firstName); // Jane
console.log(person.lastName); // Doe

在这个例子中,_firstName_lastName是私有成员变量,它们通过公开的getter和setter进行访问和修改。这样,我们可以在setter中加入逻辑来验证或修改设置的值。fullName是一个虚拟属性,没有对应的成员变量,它的getter返回一个由firstNamelastName组成的全名,setter则会解析输入的全名并设置firstNamelastName

好处

使用getter和setter的好处包括:

  • 封装性:你可以隐藏类的内部实现细节,只暴露通过getter和setter访问的接口。
  • 数据验证:在setter中,你可以添加验证逻辑来防止无效的数据被设置。
  • 附加逻辑:在访问或设置属性时,你可以执行额外的代码,比如日志记录或计算其他属性。
注意事项

虽然getter和setter提供了很好的封装和灵活性,但它们也可能使得你的代码更难理解和维护,特别是当它们包含复杂的逻辑时。因此,应当在确实需要时才使用它们。

15.TypeScript 如何允许模块外定义的类可以访问?

在TypeScript中,如果你想让模块外的代码能够访问在某个模块内定义的类,你需要导出这个类。TypeScript使用export关键字来标记可以从模块外部访问的类、接口、函数或变量。当你导出一个类,它就可以被其他模块通过import语句导入并使用。

导出类

假设你有一个Person类在person.ts文件中定义,你想在其他文件中使用这个类,你可以这样导出Person类:

// person.ts
export class Person {
    constructor(public name: string) {}
}
导入类

然后,在另一个文件中,你可以使用import语句导入Person类:

// app.ts
import { Person } from './person';

const person = new Person("John Doe");
console.log(person.name); // 输出: John Doe
默认导出

每个模块也可以有一个默认导出。如果你的模块导出一个主要的类或函数,使用默认导出可能更方便。你可以使用export default语法来实现:

// person.ts
export default class Person {
    constructor(public name: string) {}
}

当你使用默认导出时,导入时不需要使用花括号:

// app.ts
import Person from './person';

const person = new Person("Jane Doe");
console.log(person.name); // 输出: Jane Doe
注意事项
  • 保持模块简洁:尽量一个模块只做一件事,这样维护和理解代码会更容易。
  • 使用明确的导入路径:在import语句中使用相对或绝对路径来明确指定模块的位置。
  • 关注循环依赖:尽量避免模块间的循环依赖,因为它们可能导致难以调试的初始化问题。

通过这种方式,TypeScript支持模块化开发,允许开发者构建更加可维护和可复用的代码库。

由于内容太多,更多内容以链接形势给大家,点击进去就是答案了

16. 如何使用 Typescript 将字符串转换为数字?

17. 简述TypeScript 什么是 .map 文件,为什么/如何使用它?

18. 简述TypeScript 中的类是什么?你如何定义它们?

19. 请简述TypeScript 与 JavaScript 有什么关系?

20. 解释TypeScript 中的 JSX 是什么?

21. TypeScript 支持哪些 JSX 模式?

22. 请简述如何编译 TypeScript 文件?

23. TypeScript 中有哪些范围可用?这与JS相比如何?

24. 简述TypeScript 中的箭头/lambda 函数是什么?

25. 请解释rest参数和声明rest参数的规则 ?

26. TypeScript 什么是三斜线指令?有哪些三斜杠指令?

27. 简述TypeScript 中 Omit类型有什么作用?

28. TypeScript中如何实现函数重载?

29. TypeScript 如何让接口的所有属性都可选?

30. TypeScript类型anynevervoid和unknown使用场景区别?

31. TypeScript 什么是装饰器,它们可以应用于什么?

32. TypeScript 中的 any 和 unknown 有什么区别?

33. 简述什么是TypeScript 类型批注 ?

34. 简述为什么推荐使用 TypeScript ?

35. 简述TypeScript 中的泛型是什么,如何使用 ?

36. 简述TypeScript 中 interface 和 type 的差别是什么?

37. TypeScript 如何与其他工具和库集成?

38. 解释TypeScript 是如何进行类型检查的?

39. 简述如何在 TypeScript 中定义和导入/导出模块?

40. 简述TypeScript 命名空间?它与模块有何不同?

41. 在 TypeScript 中如何定义和使用命名空间?

42. 如何使用 TypeScript 创建和使用装饰器?

43. TypeScript let 和 const 有什么区别?

44. 简述TypeScript 中的 var 和 let 有什么区别?

45. 简述什么时候使用 TypeScript any type?

46. TypeScript的void类型是什么,什么时候使用?

47. 简述TypeScript 的 never type 是什么,什么时候用?

48. 简述如何在 TypeScript 中使用 async/await?

49. 解释TypeScript 如何支持类型推断?

50. 如何将多个TypeScript 文件合并为一个js文件?

51. TypeScript支持哪些面向对象的术语?

52. 简述如何在TypeScript中实现继承?

53. 简述TypeScript中const和readonly的区别是什么?枚举和常量的区别?

54. TS中的接口interface 和 type语句有什么区别?

55. 件事TypeScript的as语法是什么?

56. 举例子说明TypeScript的Enum枚举类型?

57. 简述什么是TS中的声明合并?

58. 请分别TypeScript中?. , ?? , !: , _ , ** 等符号的含义?

59. 解释Typescript的缺点 ?

60. TypeScript的有哪个3个主要的组件 ?

61. 简述我们如何获得TypeScript并安装?

62. 简述能否自动编译.ts文件,并实时修改.ts文件?

63. 简述能否自动编译.ts文件,并实时修改.ts文件?

64. JavaScript不支持函数重载,但TypeScript是否支持函数重载?

65. 请问可以调试任何TypeScript文件吗?

66. 解释什么是TypeScript定义管理器?

67. 简述什么是TypeScript Declare关键字?

68. 如何从任何.ts文件生成TypeScript定义文件?

69. 简述什么是tsconfig.son文件吗?

70. 简述什么是TypeScript映射文件?

71. 简述什么是JSX?我们可以在TypeScript中使用JSX吗?

72. 简述什么是TypeScript 匿名函数?

73. 举例子描述TypeScript中的方法重写 ?

74. 简述TypeScript常用工具库常用的常用工具库 ?

  • 28
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值