TypeScript (TS) 与 JavaScript (JS) 全维度区别 + 常见代码对比(自学用)

166 阅读8分钟

TypeScript (TS) 与 JavaScript (JS) 全维度区别 + 常见代码对比

一、TS 与 JS 核心区别(完全版)

维度TypeScriptJavaScript
本质定位强类型的 JS 超集(包含所有 JS 语法,新增类型系统)弱类型、动态类型的解释型脚本语言
类型系统静态类型(编译期检查类型)、支持显式类型注解、类型推导、泛型、接口等动态类型(运行期检查类型)、无类型注解,变量类型可随时改变
编译过程需编译为 JS 才能运行(TSC 编译器),编译期可发现类型错误直接由 JS 引擎(V8/SpiderMonkey)解释执行,错误仅运行时暴露
语言特性包含 JS 所有特性 + 新增:1. 类型注解 / 断言2. 接口(Interface)3. 泛型(Generic)4. 枚举(Enum)5. 元组(Tuple)6. 命名空间(Namespace)7. 抽象类(Abstract Class)8. 可选链 / 空值合并(语法糖,后被 ES 吸纳)仅支持 ES 标准特性(ES5/ES6+):变量、函数、类、模块、Promise 等,无类型相关特性
面向对象完整的 OOP 支持:抽象类、接口、访问修饰符(public/private/protected)ES6 后支持类和继承,但无抽象类、接口、访问修饰符(仅靠约定)
错误检测编译期检测类型错误、语法错误,提前规避 80% 运行时问题仅运行时抛出错误(如类型不匹配、未定义变量)
工具支持完美支持 IDE 智能提示(VS Code 原生支持)、重构、代码导航智能提示有限,重构易出错
兼容性需配置编译目标(ES3/ES5/ES6+),可兼容所有 JS 运行环境直接运行,但高版本 ES 特性需 Babel 转译
使用场景中大型项目、团队协作、框架开发(React/Vue/Angular 主流选型)小型脚本、快速原型、简单页面交互
学习成本高于 JS,需掌握类型系统、TS 特有语法入门简单,核心语法易掌握

二、TS 常见代码示例(附 JS 对比)

1. 变量类型注解(最基础区别)

TypeScript
// 基础类型注解
let num: number = 10; // 数字类型
let str: string = "hello"; // 字符串类型
let bool: boolean = true; // 布尔类型
let arr: number[] = [1, 2, 3]; // 数字数组
let arr2: Array<string> = ["a", "b"]; // 泛型数组
let anyVar: any = "任意类型,等同于JS变量"; // 关闭类型检查
let unknownVar: unknown = 10; // 安全版any,需类型断言才能使用

// 类型推导(无需显式注解,TS自动推断)
let age = 20; // 自动推断为number类型
age = "20"; // ❌ 编译报错:不能将字符串赋值给数字类型
JavaScript
// 无类型约束,变量类型可随意改变
let num = 10;
num = "10"; // ✅ 无报错
let arr = [1, 2, 3];
arr.push("4"); // ✅ 无报错
let anyVar = "任意类型";
anyVar = true; // ✅ 无报错

2. 函数类型(参数 / 返回值注解)

TypeScript
// 普通函数:参数+返回值注解
function add(a: number, b: number): number {
  return a + b;
}
add(1, 2); // ✅
add(1, "2"); // ❌ 编译报错:参数b应为数字

// 可选参数(?)+ 默认参数
function greet(name: string, age?: number): string {
  return `Hello ${name}, age ${age || 18}`;
}
greet("Tom"); // ✅
greet("Tom", 20); // ✅

// 剩余参数注解
function sum(...nums: number[]): number {
  return nums.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3); // ✅

// 函数类型别名
type Fn = (x: number) => number;
const double: Fn = (x) => x * 2;
JavaScript
// 无类型约束,参数/返回值任意
function add(a, b) {
  return a + b;
}
add(1, "2"); // ✅ 返回"12",隐式类型转换导致逻辑错误

// 可选参数靠判断,无语法级支持
function greet(name, age) {
  return `Hello ${name}, age ${age || 18}`;
}
greet("Tom"); // ✅

// 剩余参数无类型约束
function sum(...nums) {
  return nums.reduce((a, b) => a + b, 0);
}
sum(1, "2", 3); // ✅ 返回"123",逻辑错误

3. 接口(Interface)—— TS 特有

TypeScript
// 定义对象结构
interface User {
  id: number;
  name: string;
  age?: number; // 可选属性
  readonly gender: string; // 只读属性
}

// 实现接口
const user: User = {
  id: 1,
  name: "Tom",
  gender: "male"
};
user.gender = "female"; // ❌ 编译报错:只读属性不能修改

// 接口继承
interface Admin extends User {
  role: string;
}
const admin: Admin = {
  id: 2,
  name: "Jerry",
  gender: "male",
  role: "admin"
};

// 函数接口
interface Fn {
  (x: number, y: number): number;
}
const multiply: Fn = (x, y) => x * y;
JavaScript
// JS无接口,靠注释/约定约束对象结构
const user = {
  id: 1,
  name: "Tom",
  gender: "male"
};
user.gender = "female"; // ✅ 无约束
user.age = "20"; // ✅ 随意添加属性,无报错

// 函数无接口约束
const multiply = (x, y) => x * y;
multiply("2", 3); // ✅ 返回"23",逻辑错误

4. 类(Class)—— 增强版 OOP

TypeScript
// 类+访问修饰符+接口实现
interface Person {
  getName(): string;
}

class Student implements Person {
  public name: string; // 公有的(默认)
  private age: number; // 私有:仅类内部可访问
  protected grade: string; // 受保护:类内部+子类可访问
  readonly id: number; // 只读

  constructor(name: string, age: number, grade: string) {
    this.name = name;
    this.age = age;
    this.grade = grade;
    this.id = Math.random();
  }

  getName(): string {
    return this.name;
  }

  getAge(): number {
    return this.age; // ✅ 类内部可访问private
  }
}

class CollegeStudent extends Student {
  getGrade(): string {
    return this.grade; // ✅ 子类可访问protected
  }
}

const stu = new Student("Alice", 18, "高一");
stu.age; // ❌ 编译报错:private属性外部不可访问
stu.grade; // ❌ 编译报错:protected属性外部不可访问
JavaScript
// ES6类,无访问修饰符,靠约定(_前缀表示私有)
class Student {
  constructor(name, age, grade) {
    this.name = name;
    this._age = age; // 约定私有,实际可访问
    this._grade = grade; // 约定受保护,实际可访问
    this.id = Math.random();
  }

  getName() {
    return this.name;
  }

  getAge() {
    return this._age;
  }
}

class CollegeStudent extends Student {
  getGrade() {
    return this._grade;
  }
}

const stu = new Student("Alice", 18, "高一");
stu._age = 20; // ✅ 可直接修改“私有”属性
stu._grade = "大二"; // ✅ 可直接修改“受保护”属性

5. 枚举(Enum)—— TS 特有

TypeScript
// 数字枚举
enum Direction {
  Up, // 默认从0开始:0
  Down, // 1
  Left, // 2
  Right // 3
}
const dir: Direction = Direction.Up;
console.log(Direction[0]); // ✅ 输出"Up"(反向映射)

// 字符串枚举
enum Status {
  Success = "success",
  Error = "error"
}
const res: Status = Status.Success;

// 常量枚举(编译后不生成对象,性能更好)
const enum Color {
  Red,
  Green,
  Blue
}
const color = Color.Red;
JavaScript
// JS无枚举,靠常量对象模拟
const Direction = {
  Up: 0,
  Down: 1,
  Left: 2,
  Right: 3
};
// 无反向映射,需手动实现
const DirectionReverse = {
  0: "Up",
  1: "Down"
};
const dir = Direction.Up;
console.log(DirectionReverse[0]); // ✅ 输出"Up"

const Status = {
  Success: "success",
  Error: "error"
};
const res = Status.Success;

6. 泛型(Generic)—— TS 特有

TypeScript
// 泛型函数:复用逻辑+保留类型信息
function identity<T>(arg: T): T {
  return arg;
}
const num = identity<number>(10); // ✅ 返回number类型
const str = identity<string>("hello"); // ✅ 返回string类型

// 泛型接口
interface Result<T> {
  code: number;
  data: T;
}
const res: Result<{ name: string }> = {
  code: 200,
  data: { name: "Tom" }
};

// 泛型类
class Box<T> {
  private value: T;
  constructor(value: T) {
    this.value = value;
  }
  getValue(): T {
    return this.value;
  }
}
const numBox = new Box<number>(10);
const strBox = new Box<string>("hello");
JavaScript
// JS无泛型,只能用any,丢失类型信息
function identity(arg) {
  return arg;
}
const num = identity(10); // 类型为any
const str = identity("hello"); // 类型为any

// 模拟泛型接口,无类型约束
const res = {
  code: 200,
  data: { name: "Tom" }
};
res.data.age = "20"; // ✅ 无约束

// 模拟泛型类,无类型约束
class Box {
  constructor(value) {
    this.value = value;
  }
  getValue() {
    return this.value;
  }
}
const numBox = new Box(10);
numBox.value = "hello"; // ✅ 随意修改类型

7. 元组(Tuple)—— TS 特有

TypeScript
// 元组:固定长度+固定类型的数组
let tuple: [string, number] = ["Tom", 20];
tuple[0] = "Jerry"; // ✅
tuple[1] = 21; // ✅
tuple.push(30); // ✅ 允许追加(TS小缺陷)
tuple[2]; // ❌ 编译报错:元组索引只能是0/1

// 解构元组
const [name, age] = tuple;
console.log(name); // ✅ string类型
console.log(age); // ✅ number类型
JavaScript
// JS无元组,普通数组无长度/类型约束
let arr = ["Tom", 20];
arr[0] = 10; // ✅
arr[1] = "20"; // ✅
arr.push(true); // ✅
const [name, age] = arr;
console.log(name); // ✅ 类型为any
console.log(age); // ✅ 类型为any

8. 类型断言(Type Assertion)—— TS 特有

TypeScript
// 方式1:尖括号
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;

// 方式2:as(React中推荐)
let strLength2: number = (someValue as string).length;

// 非空断言(!):断言变量非null/undefined
function getLength(str?: string): number {
  return str!.length; // ✅ 断言str一定有值
}
JavaScript
// JS无类型断言,直接访问属性(可能报错)
let someValue = "this is a string";
let strLength = someValue.length; // ✅ 正常
someValue = null;
strLength = someValue.length; // ❌ 运行时报错:Cannot read property 'length' of null

9. 空值合并 / 可选链(TS 语法糖,后被 ES 吸纳)

TypeScript
// 可选链(?.):避免访问null/undefined属性报错
const obj = { a: { b: 10 } };
console.log(obj?.a?.b); // ✅ 10
console.log(obj?.c?.d); // ✅ undefined(无报错)

// 空值合并(??):仅当值为null/undefined时使用默认值
const num = 0;
console.log(num ?? 10); // ✅ 0(区别于||:0||10返回10)
const empty = null;
console.log(empty ?? 10); // ✅ 10
JavaScript(ES2020+ 支持,低版本需转译)
// 传统写法:嵌套判断
const obj = { a: { b: 10 } };
console.log(obj && obj.a && obj.a.b); // ✅ 10
console.log(obj && obj.c && obj.c.d); // ✅ undefined

// 传统写法:|| 存在缺陷(0/""/false会被判定为假)
const num = 0;
console.log(num || 10); // ✅ 10(不符合预期)
const empty = null;
console.log(empty || 10); // ✅ 10

三、总结

核心区别回顾

  1. 类型系统:TS 是静态类型(编译期检查),JS 是动态类型(运行期检查),TS 通过类型注解 / 接口 / 泛型等约束类型,从根源减少运行时错误。
  2. 语言特性:TS 新增接口、枚举、泛型、抽象类、访问修饰符等特性,强化面向对象和代码复用,JS 仅支持基础 ES 特性。
  3. 工程化:TS 更适合大型项目 / 团队协作,依赖编译过程提前暴露问题,JS 适合小型脚本 / 快速开发,但重构和维护成本更高。

常见代码核心差异

  1. TS 通过类型注解约束变量 / 函数 / 类的类型,JS 无任何类型约束;
  2. TS 特有接口、枚举、泛型、元组等特性,JS 需通过对象 / 常量模拟(无语法级约束);
  3. TS 对类的访问修饰符、只读属性提供语法支持,JS 仅靠约定(无强制约束)。