当前位置: 首页 > news >正文

TypeScript 入门基础:与原生 JavaScript 的详细对比

TypeScript 入门基础:与原生 JavaScript 的详细对比

前言

TypeScript 是由微软开发并维护的开源编程语言,它是 JavaScript 的一个超集。这意味着所有合法的 JavaScript 代码,同时也是合法的 TypeScript 代码。TypeScript 在 JavaScript 的基础上添加了可选的静态类型检查,让我们在开发阶段就能发现大量潜在错误,并获得更强大的编辑器智能提示与重构能力。

本文将带你从零开始学习 TypeScript 的核心基础,并在每个概念上对比原生 JavaScript,帮助你更直观地理解 TS 带来的价值。

1. 环境搭建与编译

JavaScript 的运行方式

原生 JS 可以直接在浏览器或 Node.js 中运行,无需任何编译过程。你写好一个.js文件,直接用 Node 执行或引入 HTML 即可。

TypeScript 需要编译

TypeScript 代码不能直接在浏览器或 Node.js 中运行,需要先通过TypeScript 编译器 (tsc)将其转换成 JS 代码。

安装 TypeScript:

npminstall-gtypescript

编写一个简单的hello.ts

functiongreet(name:string):string{return`Hello,${name}`;}console.log(greet("World"));

编译并运行:

tsc hello.ts# 生成 hello.jsnodehello.js# 输出: Hello, World

tsconfig.json 配置文件

实际项目中,我们通过tsconfig.json精细控制编译行为:

{"compilerOptions":{"target":"ES2020",// 编译目标 JS 版本"module":"commonjs",// 模块系统"strict":true,// 开启所有严格类型检查"outDir":"./dist","rootDir":"./src"}}

之后只需执行tsc即可编译整个项目。

对比总结:

  • JS 零配置直接运行,开发轻快但缺乏编译时检查。
  • TS 增加了编译环节,但换来的是类型安全和更早的错误发现。

2. 类型注解与类型推断

JavaScript 是一门动态类型语言:

// JS: 变量可以随时赋值为任意类型letmessage="Hello";message=42;// 完全合法,但可能引发运行时 BUG

TypeScript 允许我们为变量添加类型注解

// TS: 指定类型后,赋值其他类型会编译报错letmessage:string="Hello";message=42;// ❌ 错误: 不能将类型“number”分配给类型“string”。

基本类型

TS 支持所有 JS 原始类型,并额外增加了一些:

类型说明示例
string字符串let name: string = "Alice";
number数字let age: number = 30;
boolean布尔值let done: boolean = false;
array数组let list: number[] = [1,2,3];
tuple固定长度、类型的元组let x: [string, number];
enum枚举(后面详谈)
any任意类型,跳过检查let data: any = 5;
void无返回值(函数)function log(): void {}
null/undefined与 strictNullChecks 相关
never永远不存在的值的类型函数抛出异常或死循环
object非原始类型let obj: object = {};

类型推断

TS 很智能,能自动推断变量的类型,不必处处标注:

letgreeting="Hi";// 推断为 stringgreeting=100;// ❌ 报错,因为已经被推断为 string

这种情况与显式注解let greeting: string = "Hi"等价。

联合类型与类型别名

在 JS 中,一个函数参数既可以接收字符串也可以接收数字,通常只能在代码内判断:

// JS: 运行时判断functionprintId(id){if(typeofid==="string")console.log(id.toUpperCase());elseconsole.log(id);}

TS 可以使用联合类型清晰表达:

typeID=string|number;// 类型别名functionprintId(id:ID):void{if(typeofid==="string"){console.log(id.toUpperCase());}else{console.log(id);}}

string | number表示既可以是 string 也可以是 number,编辑器会根据类型缩小(Narrowing)提供准确的提示。

对比总结:

  • JS 的类型信息存在于运行时和开发者的脑海中,容易遗忘导致类型错误。
  • TS 的类型注解和推断将类型信息写入代码,成为“活文档”,在编码阶段就杜绝了类型不匹配的错误。

3. 接口(Interface)

JavaScript 对象是无固定形状的,函数只能靠文档或运行时的typeof去保证参数结构:

// JS: 期望 user 有 name 和 age 属性,但没有任何强制functiongetUserInfo(user){return`${user.name}is${user.age}years old`;}getUserInfo({name:"Bob"});// 运行时访问 undefined,可能造成 bug

TypeScript 使用接口来定义对象的结构:

interfaceUser{name:string;age:number;}functiongetUserInfo(user:User):string{return`${user.name}is${user.age}years old`;}getUserInfo({name:"Bob"});// ❌ 编译错误:缺少 age 属性

接口的高级特性

  • 可选属性age?: number
  • 只读属性readonly id: number
  • 函数类型接口
    interfaceSearchFunc{(source:string,subString:string):boolean;}
  • 可索引类型[index: number]: string
  • 接口继承
    interfaceAdminextendsUser{role:string;}
  • 类实现接口
    classPersonimplementsUser{name:string;age:number;constructor(name:string,age:number){this.name=name;this.age=age;}}

对比总结:

  • JS 中,对象的结构约束全靠约定和运行时检查,代码编写者需要自己保证一致性。
  • TS 的接口在编译阶段强制检查对象形状,让代码更加自文档化,也让重构变得更加安全和容易。

4. 类(Class)

ES6 为 JS 引入了类语法,但缺少访问控制符(如private)和抽象类等特性:

// JS (ES6+)classAnimal{constructor(name){this.name=name;// 没有私有化机制,约定用 _name 表示私有}speak(){console.log(`${this.name}makes a noise.`);}}

TypeScript 提供了完整的面向对象增强:

访问修饰符

  • public(默认):可自由访问
  • private:只能在类内部访问
  • protected:能在类及子类中访问
classAnimal{privatename:string;// 私有属性constructor(name:string){this.name=name;}publicspeak():void{console.log(`${this.name}makes a noise.`);}}constdog=newAnimal("Dog");dog.name;// ❌ 错误: 属性“name”为私有属性,只能在类“Animal”中访问。

参数属性

TS 允许在构造函数参数中直接声明并初始化成员,简化代码:

classAnimal{constructor(privatename:string){}// 等价于声明了一个 private name 并在构造函数中赋值}

抽象类

不能直接实例化的类,用于定义公共行为并由子类实现:

abstractclassAnimal{abstractmakeSound():void;// 抽象方法,子类必须实现move():void{console.log("moving...");}}classDogextendsAnimal{makeSound(){console.log("Woof!");}}

与 JS 私有字段 (#) 对比

ES2022 引入了真正的私有字段#name,但 TS 的private只在编译时检查,编译到 JS 后依然可访问(除非目标 ES2022 并使用#)。通常 TS 项目中更常用private修饰符。

对比总结:

  • JS 的类更简单,缺少访问控制和抽象机制,大型项目维护时容易误操作对象内部状态。
  • TS 的类通过访问修饰符和抽象类提供了更严谨的 OOP 设计,提高封装性和代码的可维护性。

5. 函数

JavaScript 函数参数无类型约束,重载需要手动处理:

// JS: 模拟重载functionadd(a,b){if(typeofa==="number"&&typeofb==="number"){returna+b;}if(typeofa==="string"&&typeofb==="string"){returna.concat(b);}}

TypeScript 函数可以定义参数和返回值的类型,还支持函数重载

基本类型声明

functionadd(a:number,b:number):number;functionadd(a:string,b:string):string;functionadd(a:any,b:any):any{returna+b;}add(1,2);// 3add("a","b");// "ab"add(1,"b");// ❌ 报错:没有与此调用匹配的重载

重载签名列表 + 一个实现函数,外部调用时只能使用已定义的重载签名,保证了类型安全。

可选参数和默认参数

functionbuildName(firstName:string,lastName?:string):string{if(lastName)return`${firstName}${lastName}`;returnfirstName;}// 或直接默认值:lastName: string = "Smith"

剩余参数

functionsum(...numbers:number[]):number{returnnumbers.reduce((acc,cur)=>acc+cur,0);}

对比总结:

  • JS 中函数参数数量和类型完全由调用方决定,类型错误要到运行时才暴露。
  • TS 通过类型注解、重载声明,使得函数调用契约一目了然,编译器会帮你检查传入的参数。

6. 泛型(Generics)

在 JavaScript 中,要想写一个能返回任意类型输入的函数,只能使用any或放弃类型:

// JS: 丢失了类型信息functionidentity(arg){returnarg;}letoutput=identity("hello");// output 是 any,没有类型提示

TypeScript 的泛型允许我们在定义时使用类型变量,调用时才确定具体类型:

functionidentity<T>(arg:T):T{returnarg;}letoutput1=identity<string>("hello");// output1 明确为 stringletoutput2=identity(42);// 类型推断为 number

泛型不仅适用于函数,还可以用于接口和类:

interfaceGenericRepository<T>{getById(id:number):T;getAll():T[];}classUserRepositoryimplementsGenericRepository<User>{getById(id:number):User{/* ... */}getAll():User[]{/* ... */}}

泛型约束

可以限制泛型必须具有某些属性:

interfaceLengthwise{length:number;}functionlogLength<TextendsLengthwise>(arg:T):T{console.log(arg.length);returnarg;}logLength("hello");// OKlogLength(123);// ❌ number 没有 length 属性

对比总结:

  • JS 无法表达“某个函数可以处理任意类型但要保持类型关系”,只能依赖any和手动类型判断。
  • TS 的泛型让我们写出既灵活又类型安全的代码,并且不丢失类型信息,编辑器能够给出准确提示。

7. 枚举(Enum)

JavaScript 没有枚举类型,通常使用常量或对象模拟:

// JS 模拟枚举constDirection={Up:0,Down:1,Left:2,Right:3};

这种方式没有类型约束,任意数字都能赋值,容易出错。

TypeScript 内置枚举

enumDirection{Up,// 默认 0Down,// 1Left,// 2Right// 3}functionmove(dir:Direction):void{// ...}move(Direction.Up);// OKmove(5);// ❌ 错误:类型“5”的参数不能赋给“Direction”

字符串枚举

enumStatus{Active="ACTIVE",Inactive="INACTIVE"}

常量枚举

const enum定义,编译时直接内联值,不生成额外的对象代码:

constenumColor{Red,Green,Blue}letc=Color.Red;// 编译后变成 let c = 0;

对比总结:

  • JS 中模拟枚举容易导致误用,且缺乏命名空间的聚合感。
  • TS 枚举提供了有名字的常量集合,使得代码可读性更强,同时受类型系统的约束,避免无效值。

8. 高级类型与工具类型(概览)

随着应用规模扩大,你还会接触到更强大的类型工具,这些都是 JavaScript 完全不具备的:

  • 交叉类型A & B同时满足多个类型
  • 类型守卫typeofinstanceof、自定义判断,帮助类型缩小
  • 类型断言as告诉编译器“我知道这是什么类型”
  • 非空断言!排除null/undefined
  • 工具类型:TypeScript 内置Partial<T>Required<T>Readonly<T>Pick<T, K>Omit<T, K>等,快速基于已有类型创建新类型。
interfaceTodo{title:string;description:string;completed:boolean;}typeTodoPreview=Pick<Todo,"title"|"completed">;// { title: string; completed: boolean }

这些特性在 JS 中只能靠人工保证,无法在编码阶段自动化验证。


9. 模块与命名空间

ES6 提供了标准的模块系统(import/export),TypeScript 完全兼容,并扩展了类型导出

// user.tsexportinterfaceUser{name:string;age:number;}exportfunctioncreateUser(name:string,age:number):User{return{name,age};}// main.tsimport{User,createUser}from"./user";constuser:User=createUser("Alice",30);

TS 还保留了“命名空间”(内部模块)的概念,用于组织代码,避免全局污染:

namespaceUtils{exportfunctionlog(msg:string):void{console.log(msg);}}Utils.log("Hi");

不过现代项目更推荐使用 ES 模块。

对比总结:

  • JS 使用 ES 模块,导入导出的是值,没有类型概念。
  • TS 的模块可以导入导出类型(interfacetype等),这些在编译后会被完全擦除,只影响编译阶段,让跨文件的类型检查成为可能。

10. TypeScript 与 JavaScript 的互操作

实际项目中,我们常常需要与纯 JS 代码或第三方库协作。TS 为此提供了多种手段:

  • 声明文件(.d.ts:为 JS 库提供类型描述,例如jquery.d.ts。社区维护的 DefinitelyTyped 提供了海量@types包,安装即可:npm install --save-dev @types/lodash
  • anyunknown:当无法确定类型时,any完全跳过检查,unknown要求使用前做类型判断,更安全。
  • 类型断言const el = document.getElementById("app") as HTMLDivElement;
  • 非空断言user!.name告诉编译器user一定不为null/undefined

从 JS 迁移到 TS,可以渐进式进行:将.js重命名为.ts,逐步添加类型注解,开启strict模式将不安全的代码暴露出来并修复。

对比总结:

  • JS 生态的海量库可以直接在 TS 中使用,TS 通过声明文件赋予了类型智能,而 JS 调用这些库时依然缺乏类型保障。

结语

TypeScript 并不是要替代 JavaScript,而是给 JavaScript 插上了“类型之翼”。它让我们在开发大型应用时,能够:

  • 在编码阶段避免常见的类型错误
  • 获得精确的智能提示重构能力
  • 写出自解释、可维护的代码

JavaScript 的灵活性依然在,但 TypeScript 让这种灵活性被约束在一个安全的边界内。正如前端框架之于原生 DOM,TypeScript 之于 JavaScript 也是开发效率的巨大提升。

如果你已经掌握了 JavaScript,那么学习 TypeScript 的成本并不高——它只是 JS 的**“类型注释版”**。希望本文的对比讲解能帮你迈出坚实的第一步,快速将 TS 应用到你的项目中。

http://www.jsqmd.com/news/865044/

相关文章:

  • SteamDeck_rEFInd:Steam Deck双系统引导管理工具完全指南 [特殊字符]
  • 多智能体与多技能区别以及优缺点,怎么选择:AI协作开发的终极对决
  • 别再死磕 Elasticsearch 了,这个轻量级搜索引擎更香
  • 2026南昌民商事纠纷律师测评:南昌专业资深代理律师推荐 - 品牌2025
  • 前端性能分析工具利器
  • 上海回升交通设施工程:黄浦正规的小区划线公司选哪家 - LYL仔仔
  • 利用Taotoken模型广场为不同应用场景选择性价比最优模型
  • 终极HTML转Figma实战指南:3步将网页秒变可编辑设计稿
  • 彻底告别Microsoft Edge:Windows系统级浏览器卸载完全指南
  • 2026 曲靖专业防水公司TOP5推荐:卫生间、外墙、楼顶、地下室渗漏专业公司推荐(2026年5月曲靖最新深度调研方案) - 防水百科
  • 从账单明细看Taotoken按Token计费模式的清晰与便捷
  • 南开区黄金回收店铺盘点 连锁分店辐射天津多地服务 - 润富黄金珠宝行
  • 隧道能见度COVI二氧化氮检测器:隧道里的“空气管家”。
  • 如何快速掌握JSON对比工具:终极效率提升指南
  • 终极指南:如何用智能脚本永久激活你的Windows和Office系统
  • 2026年软考高级——系统架构设计师预测试卷(三)
  • 江西省寄快递怎么寄最便宜?全国靠谱快递寄件平台推荐 - 时讯资讯
  • 碧蓝航线智能管家:7x24小时全自动游戏管理解决方案
  • 2026年集装箱房活动房厂家实力测评排名!7大源头工厂深度解析,采购不踩坑 - 博客万
  • 图像+语音+文本联合检索总卡顿?Gemini多模态缓存策略逆向工程,4种冷启动优化方案即刻生效
  • 魔兽争霸3终极优化指南:用WarcraftHelper让你的经典游戏重获新生
  • 英伟达季报图解:营收817亿同比增85% 净利583亿美元 黄仁勋称Agentic AI时代到来
  • claudecodec常用快捷键
  • G-Helper终极指南:5分钟让你的华硕笔记本告别臃肿,性能翻倍
  • 华恒智信助力金融行业完成“能力替代+实操答辩”的晋升体系升级
  • My-TODOs:5分钟快速上手的免费跨平台桌面待办清单终极指南
  • 从零开始在Taotoken平台创建管理密钥并获取调用示例代码
  • 2026临沂靠谱汽修排行,这10家实测值得收藏 - 速递信息
  • 悦刻母公司雾芯季报图解:营收15.9亿 靠卖电子烟净利3亿
  • 电商跨境专属!2026海南电商、跨境企业专业税务咨询机构优选 - 速递信息