ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TypeScript 类型系统与全栈项目教程

TypeScript 类型系统与全栈项目教程 TypeScript 类型系统与全栈项目教程从"图纸与施工"到"前后端签合同":系统学类型系统,并用共享类型打通全栈(TypeScript 5.x)目录00 · TS 是什么(图纸与施工)01 · 环境搭建与编译流程02 · 基础类型系统03 · 函数类型04 · 接口与类型别名05 · 类与面向对象06 · 泛型深入07 · 类型体操与工具类型08 · 项目工程化09 · 前后端共享类型10 · 实战:全栈 Todo11 · 踩坑速查12 · API 速查13 · 术语表00 · TS 是什么(图纸与施工)🏗 生活类比:两种盖楼方式JavaScript(边盖边改):施工队不画图纸直接盖。盖到一半发现"这里要放电梯但承重墙已经砌好了"——运行时才出错,改起来伤筋动骨。TypeScript(图纸先行):动工前把每一面墙、每一根管线都画进图纸(类型),监理按图验收(编译检查)——开工前就能发现承重墙和电梯的矛盾,改图纸的成本比拆墙低一百倍。TypeScript = JavaScript + 类型系统:写的是带类型的 JS,编译后"擦掉类型"变回纯 JS 运行——类型只活在开发期,运行时不产生任何额外成本。核心心智模型类型(Type)= 图纸上的规格说明:这个变量装什么、这个函数吃什么吐什么编译器(tsc)= 图纸审查员:开工前检查所有规格是否自洽类型擦除= 图纸只留在设计阶段,施工(运行)时用不到图纸运行时不检查:类型错误 100% 在编译期暴露,不增加运行时开销关键指标数值说明编译期可拦截 bug~70%微软实测数据运行时额外开销0类型被擦除IDE 效率提升30%+类型驱动补全/重构01 · 环境搭建与编译流程🏗 生活类比:设计院的工作流图纸(.ts)→ 设计院审核(tsc编译检查)→ 出施工图(生成.js)→ 施工队按图施工(node 运行)。审核不通过就不出施工图——这就是"编译失败就不产生产物"。最小工程# 初始化项目并安装 TypeScriptnpminit-ynpminstall-Dtypescript @types/node# 生成 tsconfig.json 并打开严格模式npx tsc--init--strict# 编译(src 下的 .ts → dist 下的 .js) 与 监听模式npx tsc npx tsc--watchtsconfig.json(核心配置){"compilerOptions":{"target":"ES2022","module":"commonjs","rootDir":"./src","outDir":"./dist","strict":true,"esModuleInterop":true,"skipLibCheck":true},"include":["src"]}💡strict 全家桶(建议永远开着):noImplicitAny(禁止隐式 any)、strictNullChecks(null/undefined 必须显式处理)、noUncheckedIndexedAccess(数组索引可能 undefined)——这三项拦住大多数"偷偷用 any"和"空值爆炸"。02 · 基础类型系统🏗 生活类比:建材仓库基础类型 = 标准建材:钢材(number)、木板(string)、开关(boolean)——每种建材有明确的规格。元组(tuple)= 固定尺寸的预制件([宽, 高]);枚举(enum)= 编号清单;联合类型(union)= “这面墙要么是砖要么是玻璃”;unknown= “来料未知,先质检(收窄)再用”。基础类型全览constname:string="客厅";constarea:number=42.5;constrented:boolean=false;consttags:string[]=["南向","阳光房"];/* 元组: 固定长度与类型 */constdim:[number,number]=[4,3];// [宽, 高]/* 枚举: 有名字的数字/字符串常量 */enumRoomType{Living,Bedroom,Kitchen}/* 字面量类型 + 联合类型: 值本身当类型 */typeDirection="north"|"south"|"east"|"west";letfacing:Direction="north";// ✅// facing = "up"; // ❌ "up" 不在联合里/* unknown vs any: 未知值必须先收窄 */functionparseRoom(raw:unknown):string{if(typeofraw==="string")returnraw.trim();// 收窄后安全thrownewError("bad input");}// let x: any = 1; x.foo(); // ❌ any: 类型检查完全放行, 等于没图纸/* never: 不可能的值(穷尽检查) */functionassertNever(v:never):never{thrownewError("unreachable");}类型含义典型用途number / string / boolean基础值一切数组 T[] / 元组 [T, U]列表 / 定长组列表数据 / 坐标对enum命名常量状态码、类型编号字面量 + 联合值域受限选项参数、判别联合unknown未知(安全)外部输入、JSON 解析any放弃检查(危险)尽量不用;迁移期过渡never不可能穷尽检查、抛错函数void / null / undefined无返回值 / 空副作用函数⚠any 是"没画图纸":any让该处类型检查完全失效——就像这面墙没画进图纸,监理不验收。unknown 才是安全版 any:必须收窄(typeof / instanceof / 自定义守卫)后才能用。03 · 函数类型🏗 生活类比:标准化插座一台机器(函数)的输入插头(参数)和输出接口(返回值)都有国家标准的形状——接错了插不进,插进了就能通电。泛型函数= 万能适配器:不管插头是两孔还是三孔,适配器把类型"透传"过去。函数类型:声明与用法/* 参数与返回类型 */functioncalcPrice(area:number,unit:number=100):number{returnarea*unit;}constp1=calcPrice(42.5);// 默认参数: 4250/* 可选参数 */functiondescribe(name:string,floor?:number):string{returnfloor?name+" @ "+floor:name;}/* 函数类型标注(变量/参数/回调) */typeMapper=(x:number)=number;constdouble:Mapper=(x)=x*2;functionapply(arr:number[],fn:Mapper):number[]{returnarr.map(fn);}/* 重载: 同一函数多组签名(按参数形状分发) */functionbuild(w:number,h:number):[number,number];functionbuild(size:number):[number,number];functionbuild(a:number,b?:number):[number,number]{returnb===undefined?[a,a]:[a,b];}泛型函数:类型透传
返回列表