TypeScript 面试题及详细答案 100题 (71-80)-- 模块与命名空间
《前后端面试题
》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。
文章目录
- 一、本文面试题目录
- 71. TypeScript的模块系统与ES6模块的关系是什么?如何导入/导出模块成员?
- 72. `export default`与`export`的区别?导入时的语法差异?
- 73. 什么是命名空间(Namespace)?它的核心作用是什么?
- 74. 命名空间与模块的核心区别(从作用域、文件关联、编译结果等角度分析)?
- 75. 如何在命名空间中导出和导入成员?命名空间可以嵌套吗?
- 76. 命名空间如何与模块混合使用?需要注意什么问题?
- 77. 什么是“三斜杠指令”(`/// <reference />`)?它的作用是什么?
- 78. 如何配置TypeScript的模块解析策略(`moduleResolution`)?`Node`和`Classic`的区别?
- 79. 如何在`tsconfig.json`中配置路径别名(`paths`)?需要配合什么工具生效?
- 80. 动态导入(`import()`)在TypeScript中如何使用?返回值的类型是什么?
- 二、100道TypeScript面试题目录列表
一、本文面试题目录
71. TypeScript的模块系统与ES6模块的关系是什么?如何导入/导出模块成员?
-
原理说明:
TypeScript的模块系统完全遵循ES6模块规范,两者在语法和行为上保持一致。TypeScript仅在ES6模块基础上增加了类型信息的导入/导出支持,最终编译后会转换为符合目标环境的模块语法(如CommonJS、AMD等)。
模块通过export
导出成员,通过import
导入成员,每个文件都是一个独立模块,拥有独立作用域。 -
示例代码:
// 模块 file1.ts export const name: string = "TypeScript"; export function greet(person: string): string {return `Hello, ${person}`; } export interface User {id: number;name: string; }// 模块 file2.ts // 导入指定成员 import { name, greet, User } from './file1'; console.log(name); // "TypeScript" const message: string = greet("World");// 导入并别名 import { greet as welcome } from './file1'; welcome("TypeScript");// 导入所有成员 import * as Module from './file1'; Module.greet(Module.name);
72. export default
与export
的区别?导入时的语法差异?
-
原理说明:
export
(命名导出):一个模块可以有多个命名导出,每个导出需指定名称,导入时必须使用对应名称(可别名)。export default
(默认导出):一个模块只能有一个默认导出,无需指定名称,导入时可自定义名称,无需用大括号包裹。
-
示例代码:
// 命名导出模块 export const a: number = 1; export function b(): void {}// 默认导出模块 export default class MyClass {}// 导入命名导出成员 import { a, b as funcB } from './module';// 导入默认导出成员 import MyClass from './module'; // 自定义名称// 混合导入 import MyClass, { a } from './module';
73. 什么是命名空间(Namespace)?它的核心作用是什么?
-
原理说明:
命名空间(namespace
)是TypeScript早期用于组织代码、避免全局作用域污染的方式,通过嵌套结构将相关成员(变量、函数、类等)封装在一个命名空间内。
核心作用:隔离作用域,避免命名冲突,尤其在非模块化环境中(如全局脚本)。 -
示例代码:
namespace MathUtils {export const PI: number = 3.14; // 需用export暴露export function circleArea(radius: number): number {return PI * radius **2;} }// 使用 console.log(MathUtils.PI); // 3.14 console.log(MathUtils.circleArea(2)); // 12.56// 嵌套命名空间 namespace Shapes {export namespace Circle {export function draw(): void { /* ... */ }} } Shapes.Circle.draw();
74. 命名空间与模块的核心区别(从作用域、文件关联、编译结果等角度分析)?
-** 原理说明 **:
维度 | 命名空间(Namespace) | 模块(Module) |
---|---|---|
作用域 | 可在单个文件内定义,可跨文件合并 | 每个文件是独立模块,天然隔离 |
文件关联 | 需通过/// <reference /> 关联文件 | 通过import /export 显式依赖 |
编译结果 | 编译为全局变量或IIFE(非模块化) | 编译为对应模块格式(如CommonJS) |
使用场景 | 非模块化项目、全局脚本 | 模块化项目(现代前端/后端开发) |
成员暴露 | 需显式export ,外部通过命名空间访问 | 显式export ,外部通过import 访问 |
-** 示例对比 **:
// 命名空间(单个文件内)
namespace A { export const x = 1; }
namespace A { export const y = 2; } // 合并
console.log(A.x); // 1// 模块(fileA.ts)
export const x = 1;// 模块(fileB.ts)
import { x } from './fileA';
75. 如何在命名空间中导出和导入成员?命名空间可以嵌套吗?
-** 原理说明 **:
- 命名空间内的成员需通过
export
关键字暴露,否则仅在内部可见。 - 跨文件的命名空间成员可通过
/// <reference path="filename.ts" />
指令关联后访问(同名称空间会合并)。 - 命名空间支持嵌套,内层命名空间需通过外层命名空间访问。
-** 示例代码 **:
// utils.ts
namespace Tools {export namespace StringUtils { // 嵌套命名空间export function trim(str: string): string {return str.trim();}}
}// app.ts
/// <reference path="utils.ts" /> // 关联文件
console.log(Tools.StringUtils.trim(" test ")); // "test"// 跨文件合并命名空间
// math.ts
namespace Math {export function add(a: number, b: number): number { return a + b; }
}// calc.ts
/// <reference path="math.ts" />
namespace Math { // 合并到Math命名空间export function multiply(a: number, b: number): number { return a * b; }
}// 使用
console.log(Math.add(2, 3)); // 5
console.log(Math.multiply(2, 3)); // 6
76. 命名空间如何与模块混合使用?需要注意什么问题?
-** 原理说明 **:
命名空间可以在模块内部定义(即模块内的命名空间),用于进一步组织模块内的成员;也可通过export
将命名空间作为模块成员导出,供其他模块导入。
注意事项:
- 避免过度混合,现代项目优先使用模块而非命名空间。
- 模块内的命名空间需显式导出才能被外部访问。
- 全局命名空间与模块成员可能冲突,需谨慎命名。
-** 示例代码 **:
// 模块内的命名空间(module-with-namespace.ts)
export namespace Validation { // 导出命名空间export function isEmail(str: string): boolean {return /@/.test(str);}
}// 导入并使用
import { Validation } from './module-with-namespace';
Validation.isEmail('test@example.com'); // true// 注意:避免全局命名空间与模块冲突
// global.d.ts(全局命名空间)
declare namespace GlobalNS {const version: string;
}// 模块中使用全局命名空间
console.log(GlobalNS.version); // 需确保全局声明有效
77. 什么是“三斜杠指令”(/// <reference />
)?它的作用是什么?
-** 原理说明 **:
三斜杠指令是TypeScript的特殊注释语法(/// <reference path="..." />
),用于告诉编译器依赖其他文件。其作用包括:
- 关联命名空间文件,实现跨文件命名空间合并。
- 引入类型声明文件(
.d.ts
),提供类型信息。 - 在非模块化项目中建立文件间的依赖关系。
注意:在模块化项目(使用import
/export
)中,三斜杠指令的作用被模块系统替代,通常仅用于声明文件。
-** 示例代码 **:
// types.d.ts(类型声明文件)
declare interface User {id: number;name: string;
}// app.ts
/// <reference path="types.d.ts" /> // 引入类型声明
const user: User = { id: 1, name: "Alice" }; // 可用User类型// 命名空间关联
// part1.ts
namespace Data {export const items: number[] = [1, 2, 3];
}// part2.ts
/// <reference path="part1.ts" />
namespace Data { // 合并到Data命名空间export function getFirst(): number {return Data.items[0];}
}
78. 如何配置TypeScript的模块解析策略(moduleResolution
)?Node
和Classic
的区别?
-** 原理说明 **:
moduleResolution
是tsconfig.json
中的配置项,用于指定TypeScript如何查找导入的模块。常见值为Node
(默认,模仿Node.js解析策略)和Classic
(传统TS解析策略)。
解析策略 | 核心区别 |
---|---|
Node | 遵循Node.js的require 规则:查找package.json 的main 字段、index.ts 等 |
Classic | 仅按相对路径或绝对路径查找,不处理node_modules 或package.json |
-** 配置示例 **:
// tsconfig.json
{"compilerOptions": {"moduleResolution": "Node" // 或 "Classic"}
}
-** 解析行为对比 **:
当导入import { utils } from './tools'
时:
Node
策略:查找./tools.ts
、./tools/index.ts
、./tools/package.json
的main
字段等。Classic
策略:仅查找./tools.ts
、./tools.d.ts
。
79. 如何在tsconfig.json
中配置路径别名(paths
)?需要配合什么工具生效?
-** 原理说明 **:
paths
配置允许在TypeScript中定义模块路径别名,简化长路径导入。需在tsconfig.json
的compilerOptions
中配置,同时需配合构建工具(如Webpack、Vite)或运行时工具(如ts-node)的路径映射,否则编译后可能出现路径错误。
-** 配置示例 **:
// tsconfig.json
{"compilerOptions": {"baseUrl": ".", // 必须设置,作为路径别名的基准"paths": {"@/*": ["src/*"], // 别名@映射到src目录"utils/*": ["src/common/utils/*"] // 深层别名}}
}
-** 使用与工具配合 **:
// 导入时使用别名
import { api } from '@/services/api';
import { formatDate } from 'utils/date';
需在构建工具中同步配置(以Webpack为例):
// webpack.config.js
module.exports = {resolve: {alias: {'@': path.resolve(__dirname, 'src'),'utils': path.resolve(__dirname, 'src/common/utils')}}
};
80. 动态导入(import()
)在TypeScript中如何使用?返回值的类型是什么?
-** 原理说明 **:
动态导入(import()
)是ES6的语法,TypeScript完全支持,用于在运行时异步加载模块。其返回值是一个Promise
,resolve后为模块的默认导出或命名导出对象。
TypeScript会自动推断动态导入的类型,也可通过then
的回调参数类型注解显式指定。
-** 示例代码 **:
// 模块 dynamic-module.ts
export const value: number = 100;
export default function hello(): string {return "Hello";
}// 动态导入
async function loadModule() {// 导入整个模块,类型为{ default: () => string; value: number }const module = await import('./dynamic-module');console.log(module.default()); // "Hello"console.log(module.value); // 100// 解构导入const { default: helloFunc, value: num } = await import('./dynamic-module');helloFunc(); // "Hello"
}loadModule();// 显式指定类型(可选)
import('./dynamic-module').then((module: {default: () => string;value: number;
}) => {// ...
});
二、100道TypeScript面试题目录列表
文章序号 | TypeScript面试题100道 |
---|---|
1 | TypeScript面试题及详细答案100道(01-10) |
2 | TypeScript面试题及详细答案100道(11-20) |
3 | TypeScript面试题及详细答案100道(21-30) |
4 | TypeScript面试题及详细答案100道(31-40) |
5 | TypeScript面试题及详细答案100道(41-50) |
6 | TypeScript面试题及详细答案100道(51-60) |
7 | TypeScript面试题及详细答案100道(61-70) |
8 | TypeScript面试题及详细答案100道(71-80) |
9 | TypeScript面试题及详细答案100道(81-90) |
10 | TypeScript面试题及详细答案100道(91-100) |