TS常见面试题(二)

300 阅读11分钟

本篇主讲TypeScript 的 tsconfig.json 中常见的面试题

TypeScript 的 tsconfig.json 中有哪些配置项信息?

  1. files:一个包含指定文件的相对或绝对路径的数组列表,用于指定待编译文件。编译器只会编译在 files 中列出的文件,其他文件将被忽略。

    例如:

    jsonCopy code
    "files": [  "src/main.ts",  "src/utils.ts"]
    
  2. includeexclude:用于指定要编译的文件或排除的文件的规则。

    include 是一个包含文件或文件夹的数组,用于匹配要编译的文件。它使用 glob 模式进行匹配。

    exclude 是一个包含文件或文件夹的数组,用于排除不想编译的文件。也使用 glob 模式进行匹配。

    例如:

    jsonCopy code
    "include": [  "src/**/*.ts"],
    "exclude": [  "src/**/*.test.ts",  "node_modules"]
    
  3. compileOnSave:设置为 true 后,IDE 在保存文件时会根据 tsconfig.json 重新生成文件。

  4. extends:可以通过指定另一个 tsconfig.json 文件的路径,来继承该配置文件中的配置。这对于共享一些通用配置非常有用。

    例如:

    jsonCopy code
    "extends": "./configs/base-tsconfig.json"
    
  5. compilerOptions:这是最重要的部分,用于配置 TypeScript 编译器的选项。

    compilerOptions 中,您可以设置一系列选项,如输出目标 (target)、模块化系统 (module)、是否启用严格模式 (strict)、输出目录 (outDir) 等。

    例如:

    jsonCopy code
    "compilerOptions": {
      "target": "ES6",
      "module": "CommonJS",
      "strict": true,
      "outDir": "./dist"
    }
    

    这些是 tsconfig.json 中最常用的配置项,它们使您能够对 TypeScript 项目进行高度定制化的配置,以满足您的编译需求。

我没搞懂files和include的区别

没问题,让我来解释一下 filesincludetsconfig.json 中的区别。

  1. files

    使用 files 配置,您需要逐个列出每个要编译的文件的路径,不支持使用通配符来匹配多个文件。

    例如:

    jsonCopy code
    "files": [  "src/main.ts",  "src/utils.ts"]
    

    在这个例子中,只有 src/main.tssrc/utils.ts 这两个文件会被编译,其他任何 TypeScript 文件都会被排除。

  2. include

    它使用 Glob 模式来匹配文件路径。

    使用 include 配置,您可以使用通配符来匹配多个文件或目录,从而更灵活地选择要编译的文件。

    例如:

    jsonCopy code
    "include": [  "src/**/*.ts",  "test/**/*.ts"]
    

    在这个例子中,所有位于 srctest 目录以及它们的子目录下的 .ts 文件都会被包含在编译过程中。

    关键区别:

    • files 是显式列出要编译的文件的路径,不支持通配符匹配,只编译指定的文件。
    • include 是使用 Glob 模式匹配要编译的文件或目录,支持通配符匹配,可以灵活选择要编译的文件。

通常情况下,建议使用 include 配置来选择要编译的文件,因为它提供了更大的灵活性和便利性。使用 files 配置通常是在一些特殊情况下,您确切知道要编译的文件并且不需要灵活性时使用。

相同点:

data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20version=%271.1%27%20width=%2738%27%20height=%2738%27/%3e

  1. 都是数组类型,可以包含多个文件路径或匹配模式。
  2. 都用于告诉 TypeScript 编译器哪些文件需要参与编译。

什么是glob模式

Glob 模式是一种用于匹配文件路径的简单模式匹配规则。它通常用于命令行和构建工具中,用于选择文件或目录,或者进行文件路径的模式匹配。

在 Glob 模式中,可以使用通配符来匹配文件路径的不同部分。以下是一些常用的通配符:

  • `` :匹配任意字符,除了路径分隔符 /
  • * :匹配任意数量的目录,用于递归匹配子目录。
  • ? :匹配单个字符。
  • [] :匹配括号中的任意字符。
  • {} :匹配大括号中逗号分隔的多个模式中的一个。
  • ! :在模式的开头用于否定匹配。

例如,假设我们有以下文件结构:


- src
  - utils
    - helper.ts
    - utility.ts
  - main.ts
- test
  - test-utils.ts

以下是一些 Glob 模式的示例及其匹配结果:

  • src/*.ts:匹配 src 目录下所有的 .ts 文件,结果为 src/main.ts
  • src/**/*.ts:匹配 src 目录及其所有子目录下的 .ts 文件,结果为 src/main.tssrc/utils/helper.tssrc/utils/utility.ts
  • */*.ts:匹配项目中所有子目录中的 .ts 文件,结果为 src/main.tssrc/utils/helper.tssrc/utils/utility.tstest/test-utils.ts
  • */test-*.ts:匹配所有文件名以 test- 开头且扩展名为 .ts 的文件,结果为 test/test-utils.ts

Glob 模式提供了一种简单而强大的方法来选择和匹配文件路径,特别是在构建和管理项目时非常有用。在 tsconfig.json 中,includeexclude 配置项使用的就是 Glob 模式,以指定要编译的文件和排除的文件。

compileOnSave:true 让IDE在保存文件的时候根据tsconfig.json重新生成文件。

这里重新生成,生成的是什么文件

设置 compileOnSave: true 后,IDE 在保存 TypeScript 文件时,会根据 tsconfig.json 中的配置重新生成文件。这里所说的重新生成文件指的是将 TypeScript 文件编译为 JavaScript 文件,并根据 compilerOptions 中的配置项生成对应的 JavaScript 代码。

具体来说,生成的文件包括:

  1. JavaScript 文件:对应的 TypeScript 文件会被编译为 JavaScript 文件,并输出到指定的输出目录(通过 outDir 配置项指定)。
  2. Map 文件:TypeScript 编译器会生成对应的 .map 文件,用于在调试时将编译后的 JavaScript 代码映射回原始 TypeScript 代码。这对于在浏览器中调试时很有用,因为它允许开发者在浏览器的开发者工具中看到 TypeScript 源码的调试信息。
  3. 声明文件(.d.ts 文件) :如果 TypeScript 文件中使用了声明文件( .d.ts)或配置了 declaration: true,编译器会生成对应的声明文件,用于描述 TypeScript 文件中定义的类型、接口、类等信息。这对于将 TypeScript 代码作为库包供他人使用时,提供类型信息是非常有用的。

因此,compileOnSave: true 选项会在保存 TypeScript 文件时触发 TypeScript 编译器重新生成 JavaScript 文件以及相关的辅助文件,确保项目中的代码始终保持最新的状态。这对于实时检测代码错误和调试非常有用,并且确保生成的 JavaScript 代码符合项目的配置要求。

data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20version=%271.1%27%20width=%2738%27%20height=%2738%27/%3e

和noemit区别是什么

noEmitcompileOnSave 是 TypeScript 配置中两个不同的选项,它们的作用和影响有一些区别。

  1. noEmit

    • noEmit 是 TypeScript 编译选项中的一个配置项,它用于控制 TypeScript 编译器是否生成任何输出文件(即是否生成编译后的 JavaScript 文件)。
    • noEmit 设置为 true 时,TypeScript 编译器将不会生成任何输出文件,即使在编译过程中没有出现错误也不会产生编译后的 JavaScript 文件。
    • 这对于只进行类型检查而不需要实际生成 JavaScript 文件的情况很有用,比如在开发阶段只关注类型检查,而不需要实际运行代码的情况。
  2. compileOnSave

    • compileOnSave 是一种 IDE(集成开发环境)特有的配置选项,它并不是 TypeScript 编译器的选项,而是用于在 IDE 中控制在保存文件时触发 TypeScript 编译器重新编译。
    • compileOnSave 设置为 true 时,IDE 在保存 TypeScript 文件时会触发 TypeScript 编译器重新编译该文件,根据项目中的 tsconfig.json 中的配置重新生成 JavaScript 文件以及相关的辅助文件(如声明文件和 Map 文件)。
    • 这样可以在保存文件后立即看到最新的编译结果,并在 IDE 中实时检测代码错误。

因此,noEmit 主要用于控制 TypeScript 编译器是否生成编译后的 JavaScript 文件,而 compileOnSave 则是用于 IDE 中实现在保存文件时触发编译的功能,以便及时反馈编译结果和代码错误。这两个选项分别对应了不同的编译阶段,分别是是否生成输出文件和何时触发编译过程。

详解一下compilerOptions

"compilerOptions": {
  "target": "ES6",
  /* 
  指定编译的目标 ECMAScript 版本。
  可选值有 "ES3""ES5""ES6""ES2015" 等。
  选择不同的目标版本会影响编译后代码的兼容性和特性支持。
  */

  "module": "CommonJS",
  /*
  指定生成的模块化代码的模块系统。
  可选值有 "CommonJS""AMD""ES6""System" 等。
  选择不同的模块系统可以适应不同的项目环境。
  */

  "outDir": "./dist",
  /*
  指定输出目录,即编译后的 JavaScript 文件输出的位置。
  该路径是相对于 tsconfig.json 文件的位置。
  */

  "strict": true,
  /*
  启用严格的类型检查选项。
  设置为 true 表示启用所有严格检查,包括 noImplicitAny、strictNullChecks、strictFunctionTypes 等。
  */

  "esModuleInterop": true,
  /*
  启用该选项后,TypeScript 将使用更简洁的导入语法以兼容 CommonJS 和 ES6 模块系统之间的交互。
  例如,import * as module from 'module' 将被转换为 const module = require('module')。
  */

  "allowJs": true,
  /*
  允许编译器编译 JavaScript 文件。
  这在迁移现有 JavaScript 代码到 TypeScript 时很有用,以便 TypeScript 可以对 JavaScript 文件进行类型检查。
  */

  "checkJs": true,
  /*
  启用对 JavaScript 文件的类型检查。
  该选项与 allowJs 配合使用,用于在 JavaScript 文件中进行类型检查,以捕获潜在的类型错误。
  */

  "noEmit": true
  /*
  设置为 true 后,TypeScript 编译器不会生成任何输出文件。
  这对于只进行类型检查而不需要生成 JavaScript 文件的情况很有用。
  */
}

问:allowjs,什么意思,还可以对js做类型检查?js里面没有声明类型怎么办

对的,allowJs: true 允许 TypeScript 编译器编译 JavaScript 文件,并且即使 JavaScript 文件没有显式声明类型,TypeScript 仍然会尝试进行类型检查。

在 TypeScript 中,如果启用了 allowJs 选项,TypeScript 编译器会将 JavaScript 文件视为动态类型(Dynamic Typing)的代码,并尝试根据代码的上下文推断变量和函数的类型。虽然 JavaScript 自身是一门动态类型语言,没有显式的类型声明,但 TypeScript 能够根据变量的使用情况和运算符的操作等信息推断出潜在的类型。

例如,在以下 JavaScript 代码中:

javascriptCopy code
function add(a, b) {
  return a + b;
}

const result = add(5, 10);
console.log(result);

allowJs: true 时,TypeScript 会尝试根据函数 add 的使用推断出参数 ab 可能是数字类型,并返回一个数字类型。然后,它会根据 result 变量的使用推断出它是一个数字类型,并且在类型检查时,如果出现 add 函数参数类型错误或 result 变量类型错误的情况,TypeScript 会给出相应的类型错误提示。

虽然 TypeScript 可以对 JavaScript 文件进行类型推断和类型检查,但是由于 JavaScript 本身没有显式的类型声明,所以推断的准确性可能受限。因此,如果想要更精确地进行类型检查,建议在 JavaScript 代码中添加 TypeScript 的类型声明,或者将代码逐步转换为 TypeScript 文件。这样可以确保类型检查的准确性,并获得更多 TypeScript 的类型优势。

TypeScript 中如何设置模块导入的路径别名?

通过 tsconfig.json 中的 paths 项来配置:


json复制代码
{
  "compilerOptions":
    {      "baseUrl": ".",
      "paths": {
         "@helper/*": ["src/helper/*"],
         "@utils/*": ["src/utils/*"],
         ...
      }
   }
}

解析

baseUrl: "." 表示 TypeScript 编译器在解析模块导入时的基本路径(Base Path)。换句话说,当编译器遇到类似于 importrequire 的语句时,会将这个基本路径作为起点来解析导入的模块路径。

在上面的配置中,baseUrl 被设置为 "." ,意味着 TypeScript 编译器会将当前项目的根目录作为起始路径来解析模块导入。这样配置后,当我们在项目中使用绝对路径导入模块时,可以更简洁地引用模块,不需要写出完整的相对路径。

例如,假设有以下文件结构:

cssCopy code
- src
  |- helper
  |  |- helper1.ts
  |  |- helper2.ts
  |- utils
  |  |- utils1.ts
  |  |- utils2.ts
  |- main.ts
- tsconfig.json

有了上述配置后,我们可以在 main.ts 文件中这样导入模块:

typescriptCopy code
import { something } from "@helper/helper1";
import { doSomething } from "@utils/utils1";

编译器会根据 baseUrlpaths 配置将这些模块导入正确地解析为实际的路径,即:

  • @helper/* 会被解析为 src/helper/* ,所以 @helper/helper1 导入实际指向 src/helper/helper1.ts
  • @utils/* 会被解析为 src/utils/* ,所以 @utils/utils1 导入实际指向 src/utils/utils1.ts

这样配置可以帮助我们简化模块导入的路径,使代码更具可读性和可维护性。

关于 paths 属性,它是一个映射对象,用于将自定义的模块路径别名映射到实际的文件路径。在上面的例子中,我们定义了 @helper/*@utils/* 别名,并将它们映射到 src/helper/*src/utils/* 的路径。由于 paths 属性允许定义多个映射,所以它接收一个数组来表示多个映射。每个映射定义中,键表示别名,值表示实际的文件路径。