[Typescript学习笔记-01]从VS创建的TypeScript项目结构说起
在基于Visual Studio项目中一个典型的项目结构包含了源码、包管理、编译器配置和环境定义文件。它以 app.ts 为核心通过 npm run build 将业务逻辑编译为可运行的 app.js。同时编译器会自动提取不含运行逻辑的 app.d.ts 声明文件作为“说明书”为其他模块提供类型类型检查与代码补全。为了解决“开发与运行环境不一致”的问题项目引入 app.js.map 作为翻译桥梁让开发者在 VS 中能直接基于 .ts 源码进行丝滑断点调试而 tsconfig.json 的严格模式则在编译期提前拦截 undefined 等运行时崩溃风险。1. 核心配置文件tsconfig.jsonTypeScript编译器的核心配置文件。它定义了编译选项、指定了包含或排除的文件、以及控制生成JavaScript文件的规则package.json项目的基础配置文件。记录了项目的元数据名称、版本、运行脚本Scripts以及项目所依赖的npm包Dependenciespackage-lock.json锁定文件。自动生成用来记录确切安装的第三方包版本和依赖树确保团队开发时安装的环境完全一致eslint.config.js代码规范与检测Linter配置文件。用于检查代码中的语法错误、潜在漏洞以及规范代码的书写风格。1.1 tsconfig.json如下所示是默认的配置内容{// Visit https://aka.ms/tsconfig to read more about this filecompilerOptions:{// File Layout// rootDir: ./src,// outDir: ./dist,// Environment Settings// See also https://aka.ms/tsconfig/modulemodule:nodenext,target:esnext,types:[],// For nodejs:// lib: [esnext],// types: [node],// and npm install -D types/node// Other OutputssourceMap:true,declaration:true,declarationMap:true,// Stricter Typechecking OptionsnoUncheckedIndexedAccess:true,exactOptionalPropertyTypes:true,// Style Options// noImplicitReturns: true,// noImplicitOverride: true,// noUnusedLocals: true,// noUnusedParameters: true,// noFallthroughCasesInSwitch: true,// noPropertyAccessFromIndexSignature: true,// Recommended Optionsstrict:true,jsx:react-jsx,verbatimModuleSyntax:true,isolatedModules:true,noUncheckedSideEffectImports:true,moduleDetection:force,skipLibCheck:true,}}该配置基于现代 TypeScript 技术栈全面融入了Node.js (ESM) 的最佳实践并开启了多项高阶类型安全开关。文件布局 (File Layout)本组配置用于定义项目的目录结构控制源代码的输入位置以及编译产物的输出位置。当前在模板中处于注释状态。rootDir: ./src指定 TypeScript 源代码的根目录。编译器会以此目录为基准在输出时完整保持其内部的文件夹目录结构outDir: ./dist指定编译后的 JavaScript 代码及相关产物的输出目录。若不开启此项编译出的.js、.d.ts和.map文件会直接生成在原.ts文件的同级目录下。环境设置 (Environment Settings)本组配置用于设定项目所处的运行时环境决定 TypeScript 如何理解模块之间的引用关系以及如何加载全局的类型定义。module: nodenext告诉编译器使用现代 Node.js 的模块解析算法。它完美支持 ECMAScript 模块的import/export语法并会严格根据package.json中的type: module来决定如何处理模块target: esnext指定编译后的 JavaScript 语言版本。esnext意味着支持最新的 JS 语法特性。如果你的运行环境是现代 Node.js这能带来最高的执行效率types: []限制全局类型的自动引入。设置为真空数组[]可以防止 TypeScript 自动加载node_modules/types下的所有全局类型能有效加快编译速度避免全局类型污染。输出文件控制 (Other Outputs)本组配置用于控制除核心 JavaScript 代码之外的代码产物主要用于提升开发期间的调试体验以及模块被其他项目引用时的代码复用性。sourceMap: true生成.js.map源码映射文件。在开发调试时允许调试工具将编译后的 JS 运行代码映射回最原始的.ts源代码大幅提升报错定位效率declaration: true自动生成.d.ts类型声明文件。文件内只保留类型定义而不含任何运行逻辑便于将当前项目作为 npm 包导出给其他模块使用declarationMap: true生成.d.ts.map类型声明映射文件。当外部项目引用此项目的编译产物并点击“转到定义”时能直接精准跳转回原本的.ts源码位置而非只看到纯文本声明。严格类型检查 (Stricter Typechecking Options)本组配置属于高级类型安全开关通过更严苛的语法审查在编译阶段最大化地拦截可能导致系统崩溃的隐式空值或类型边界问题。noUncheckedIndexedAccess: true强校验通过动态索引访问对象或数组时的潜在空值风险。读取动态键如obj[key]或arr[i]时TS 会强制在推导类型中附带| undefined在编译期拦截经典的“Cannot read properties of undefined”运行时报错exactOptionalPropertyTypes: true严格区分“未提供该属性”与“显式传入undefined”。若对象定义了可选属性age?: number开启此项后你可以不传age但不再允许显式传入带有undefined值的对象如{ age: undefined }。代码风格与错误预防 (Style Options)本组配置旨在规范团队的代码书写习惯开启后可在构建时充当轻量级的 Linter类似 ESLint角色清除潜在的代码逻辑死角与垃圾死代码。当前在模板中处于注释状态。noImplicitReturns: true强制要求函数内部的所有分支路径都必须有显式的return返回值防止因漏写某个分支的返回而隐式抛出undefinednoImplicitOverride: true在面向对象开发中子类重写父类方法时必须显式加上override关键字防止因拼错方法名或父类方法变更导致重写意外失效noUnusedLocals: true禁止代码中存在已声明但从未被使用的局部变量在编译阶段强制提醒开发人员及时清理冗余的代码noUnusedParameters: true禁止函数中存在定义了但完全没有在函数体中被读取和使用的入参保持函数签名的干净整洁noFallthroughCasesInSwitch: true在switch-case结构中如果一个分支内包含代码逻辑则强制要求必须以break或return结尾防止因粗心导致逻辑无故“穿透”到下一个 casenoPropertyAccessFromIndexSignature: true对于允许任意键的对象带有索引签名禁止使用点语法obj.key访问强制必须使用方括号语法obj[key]从视觉上明确提示该属性可能不存在。官方推荐与核心构建选项 (Recommended Options)本组配置是现代前沿工程标准的标准配置用于规范最新的语法编译模式、强制模块隔离并最大程度地优化大型项目的构建速度。strict: true一键开启 TypeScript 的标准严格模式。自动打包启用了包括严格空值检查、禁止隐式 any 在内的一系列高标准审查规则是高质量项目的基石jsx: react-jsx支持并配置 JSX 语法的编译模式主要针对 React。采用 React 17 引入的新 JSX 运行时编译时会自动按需引入对应的 JSX 处理逻辑开发者无需在文件顶部手动编写import ReactverbatimModuleSyntax: true强制并简化严格的模块导入与导出语法。它要求纯类型导入必须显式写为import type在最终编译成 JS 时这些纯类型会被 100% 剥离杜绝运行时因为引入仅用于类型的源码文件而报错isolatedModules: true确保项目中的每个.ts文件都可以被独立安全地转译。这能确保项目与 Vite、esbuild、Babel 等现代非官方单文件快速转译工具保持 100% 的完美兼容noUncheckedSideEffectImports: true严格校验副作用导入文件的存在性。若在代码中写入了不带变量的副作用引入例如import ./style.cssTS 编译器在构建时会切实检查该文件是否存在路径写错将立即中止构建moduleDetection: force强制将所有的.ts文件均作为独立的“模块”对待。即使文件内没有任何一条import或export也会将其包裹进模块作用域彻底防止不同文件间因为同名变量定义而产生致命的全局变量冲突skipLibCheck: true跳过对所有第三方依赖库.d.ts的类型检查。这能大幅缩短编译和构建时间同时避免因为某个第三方依赖库类型写得不规范、或是内部版本冲突而导致你自己的项目莫名其妙构建失败。1.2 package.json如下所示是默认的配置内容:{name:app1,version:1.0.0,description:,main:app.js,scripts:{test:echo \Error: no test specified\ exit 1,build:tsc --build,clean:tsc --build --clean},keywords:[],author:,license:ISC,type:commonjs,devDependencies:{types/node:^26.2.0,eslint:^10.8.1,typescript:^7.0.2}}该文件是 Node.js 项目的身份证与控制中心负责管理项目元数据、自动化脚本以及开发阶段的第三方依赖包。项目基础元数据 (Project Metadata)本组配置用于定义项目的基本信息主要在项目发布、团队协作或作为 npm 包被他人引用时发挥识别作用。name: app1定义项目的名称。在整个 Node.js 生态中该名称应保持唯一若发布到 npm 仓库它将作为包名version: 1.0.0定义当前项目的版本号。遵循语义化版本规范Semantic Versioning格式通常为“主版本号.次版本号.修订号”description: 项目的简短描述信息。用于向团队成员或社区简要说明该项目的功能和用途keywords: []项目关键词数组。以字符串列表形式存储用于在 npm 官方网站上帮助他人通过搜索发现该项目author: 项目作者的信息。可以是一个简单的姓名字符串也可以包含作者的邮箱和个人主页网址license: ISC指定项目的开源软件许可证。ISC是一种与 MIT 许可证高度相似的、极其宽松的开源协议允许他人自由复用代码。运行脚本命令 (Scripts Control)本组配置定义了一系列可以通过命令行快速触发的自动化快捷脚本通过npm run 脚本名执行极大简化了项目构建、测试和清理的流程。main: app.js指定项目的程序入口文件。当其他模块通过require(app1)引入该项目时系统会自动加载此项指定的app.js文件test项目测试脚本。当前为默认生成的占位命令echo Error: no test specified exit 1执行时会抛出错误提示并中止提醒开发者尚未配置测试框架build项目编译脚本。执行npm run build时会触发tsc --build命令采用 TypeScript 增量编译模式对整个项目进行快速构建clean构建清理脚本。执行npm run clean时会触发tsc --build --clean命令用于彻底删除上一次编译生成的缓存文件如.tsbuildinfo和输出的 JavaScript 产物确保下次是干净的全新编译。模块系统设定 (Module System)本配置用于告知 Node.js 运行时该如何解析和执行当前项目内部的所有 JavaScript 文件。type: commonjs强制声明项目采用CommonJS模块规范即使用require/module.exports。深度同步提醒之前配置的tsconfig.json中使用了现代的module: nodenext而此处写的是commonjs。这意味着 TypeScript 在编译代码时会采用兼容旧版 Node.js 的 CommonJS 规范输出这与现代的 ECMAScript 模块ESM有所不同。开发环境依赖 (Development Dependencies)本组配置记录了项目在开发和构建阶段所必须的第三方工具包。这些包在最终部署到生产环境Production时不会被包含进去有效精简了线上产物体积。types/node: ^26.2.0Node.js 核心运行时的 TypeScript 类型声明文件。它为path、fs以及全局对象如process提供完整的强类型支持与代码补全eslint: ^10.8.1现代代码静态分析检查工具Linter。配合项目中的eslint.config.js在开发期间实时检测并指出代码中的语法错误和风格缺陷typescript: ^7.0.2TypeScript 编译器的核心核心包。提供tsc命令是负责将.ts源代码转换为能够在 Node.js 中执行的.js文件的幕后核心功臣。注版本号前的^符号如^7.0.2表示版本锁定规则。它允许团队成员在执行npm install时自动升级安装兼容当前大版本的最新次版本例如允许升级到7.1.0但不允许升级到8.0.0以此保持开发工具的安全性与兼容性。2. 源代码与编译产物app.ts你编写的 TypeScript 源代码文件。项目的主要业务逻辑都在此类文件中编写app.js由app.ts编译生成的 JavaScript 文件。浏览器或 Node.js 环境实际运行的是这个文件app.js.mapSource Map源码映射文件。它将编译后的app.js映射回原代码app.ts方便你在浏览器或 VS 中直接调试 TypeScript 源码而不用去读混淆后的 JS。该文件具有如下的格式。假设我们在app.ts编写了如下的JavaScript代码functiongreet(person:string,date:Date){console.log(Hello${person}, today is${date}!);}greet(Alice,newDate);按照默认的配置编译后保存到app.js后的内容use strict;Object.defineProperty(exports,__esModule,{value:true});functiongreet(person,date){console.log(Hello${person}, today is${date}!);}greet(Alice,newDate);//# sourceMappingURLapp.js.map作为两者映射文件的app.js.map内容如下{version:3,file:app.js,sourceRoot:,sources:[app.ts],names:[],mappings:AAAA,MAAM,UAAU,KAAK,CAAC,MAAa,EAAE,IAAS;IAC5C,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,cAAc,IAAI,GAAG,CAAC,CAAC;AACpD,CAAC;AAED,KAAK,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC}映射文件每一项属性说明如下version: 3指定 Source Map 的规范版本。3是目前业界通用的最新、最成熟的标准版本体积更小解析速度更快file: app.js指定被映射的目标文件名称。表明当前这个.map文件是为哪个生成的 JavaScript 文件提供服务的sourceRoot: 指定源文件的根路径。留空空字符串表示源文件与当前的.js、.map文件处于同级目录或使用的是相对路径sources: [app.ts]原始源代码文件的路径列表。本项表明app.js是由app.ts这个文件编译而来的names: []在代码混淆/压缩时用到的原始变量名或函数名列表。由于当前项目仅做编译、未做生产打包和变量名缩写混淆通常通过 Webpack/UglifyJS 处理因此该数组为空。虽然mappings看起来像乱码但通过解密这串编码其中分号;代表换行逗号,代表代码片段的分隔我们可以精准还原出你刚才在app.ts里写的源代码。通过反向解码可以得知你的app.ts包含一个带有类型注解的函数及其调用逻辑结构如下functiongreet(person:string,date:Date){console.log(Hello${person}, today is${date});}greet(Alice,newDate());具体的调试工作原理如下执行阶段当你运行app.js时如果程序报错或者你在 Visual Studio 中打了断点。读取映射调试器如 VS 调试引擎会注意到app.js文件末尾通常有一行注释如//# sourceMappingURLapp.js.map并自动加载这个.map文件。精准定位当app.js报错在第 3 行时调试器查阅该文件的mappings字段发现第 3 行对应的是app.ts的第 2 行即console.log那一行于是直接在你的编辑界面把断点或报错红线停留在app.ts上。3. 类型声明文件app.d.tsTypeScript 类型声明文件。只包含代码的类型定义接口、类声明等不包含具体实现。常用于向没有静态类型的 JavaScript 代码提供代码补全和类型检查。app.d.ts.map声明文件的映射文件。让你在其他模块中点击“转到定义”时能直接精准跳转到原本的 .ts 源码位置。对于上面在app.ts定义的greet函数我们可以使用前export关键字将其导出。exportfunctiongreet(person:string,date:Date){console.log(Hello${person}, today is${date});}由于package.json中设置了type: commonjs而CommonJS 规范与 ECMAScript 模块ESM规范的底层设计原理和语法机制完全不同不能使用现代的默认导出 export default 语法。所以我们需要你将此设置修改为type: module。修改后并实施编译我们会在app.d.ts文件中看到如下的导出声明exportdeclarefunctiongreet(person:string,date:Date):void;//# sourceMappingURLapp.d.ts.map作为映射文件的app.d.ts.map文件则具有如下的内容{version:3,file:app.d.ts,sourceRoot:,sources:[app.ts],names:[],mappings:AAAA,wBAAgB,KAAK,CAAC,MAAM,EAAC,MAAM,EAAE,IAAI,EAAC,IAAI,QAE7C}只有在一种情况下你才需要手动去写.d.ts当你在项目里引入了一个纯 JavaScript 编写的第三方库比如十年前写的旧插件里面没有 TypeScriptTS 编译器看不懂它。此时你需要手动写一个 .d.ts文件作为翻译官告诉 TypeScript 这个纯 JS 文件里导出了什么函数、参数是什么类型。而对于你自己写的app.ts请永远直接在.ts源码中导出剩下的.d.ts生成工作交给编译器即可。4. 缓存与文档tsconfig.tsbuildinfoTypeScript 增量编译的缓存文件。记录上一次编译的状态使得下一次编译时只处理修改过的文件极大提高编译速度;CHANGELOG.md项目更新日志。用 Markdown 格式记录项目每个版本的迭代修改历史、新增功能及修复的 Bug。

相关新闻

最新新闻

日新闻

周新闻

月新闻