Skip to content

第1章 初识TypeScript

本章定位:从Python开发者的视角,认知TypeScript是什么、为什么需要它、以及如何搭建开发环境。通过与Python的对比,帮助你建立对TypeScript的第一印象。


TypeScript由微软工程师Anders Hejlsberg(也是C#之父)于2012年设计开发。最初目的是解决JavaScript在大型项目中的可维护性问题。如今TypeScript已成为前端领域最流行的语言之一,被用于Angular框架、VS Code编辑器和许多现代Web应用。

版本演进:

  • 2012年:TypeScript 0.8 发布
  • 2014年:TypeScript 1.0 正式发布
  • 2016年:TypeScript 2.0 发布,添加了非空类型、控制流分析等重要特性
  • 2018年:TypeScript 2.7 引入了固定分配类型推断
  • 2020年:TypeScript 4.0 引入了可变元组类型
  • 2023年:TypeScript 5.0 引入了装饰器标准化支持
  • 2024年至今:持续迭代,最新版本性能与功能双提升

TypeScript是JavaScript的超集(superset),这意味着:

  1. 任何有效的JavaScript代码都是有效的TypeScript代码
  2. TypeScript最终会被编译(transpile)成JavaScript来运行
  3. TypeScript添加了可选的静态类型、接口、泛型等高级特性

Python对比:Python是解释型语言,代码直接由Python解释器执行。TypeScript需要先编译(转译)为JavaScript,这类似于Python的.py文件被CPython解释器读取前的预处理过程,只是TypeScript的编译是显式的、强制性的。

TypeScript源码 (.ts/.tsx)
↓ [tsc编译器转译]
JavaScript代码 (.js)
↓ [Node.js或浏览器执行]
程序运行结果

编译器(tsc)负责:

  • 类型检查
  • 语法转译(将新语法转为ES5/ES6等兼容版本)
  • 输出优化

静态类型检查能在编译阶段发现大量错误,而不是等到运行时才暴露问题。

// TypeScript 编译错误示例
function divide(a: number, b: number): number {
return a / b;
}
const result: string = divide(10, 2); // 错误:不能将number赋值给string

Python的等效代码(无编译时检查):

def divide(a: float, b: float) -> float:
return a / b
result: str = divide(10, 2) # Python解释器不报错,只有运行才知道类型不匹配

属性TypeScriptJavaScriptPython
类型系统静态类型(可选)动态类型动态类型(可选type hint)
编译/解释编译为JS后运行解释执行解释执行
执行环境Node.js/浏览器/其他JS引擎Node.js/浏览器/其他JS引擎CPython/PyPy/其他Python实现
类型检查时机编译时(强制)无(运行时)无强制编译时检查
null/undefined有明确区分两者混用只有None
面向对象类、接口、抽象类、泛型原型链继承类、继承、多继承
函数式编程支持(箭头函数、高阶函数)支持支持(lambda、map、filter)
模块系统ES Modules + namespaceCommonJS/ES Modulesimport/from
主要用途前端/后端/Node.js全栈前端/后端/Node.js全栈后端/数据科学/脚本/AI

JavaScript(动态类型):

let x = 10; // number
x = "hello"; // 完全合法,类型可以随时改变
x = [1, 2, 3]; // 数组也没问题

TypeScript(静态类型,可选):

let x: number = 10; // 显式类型标注
x = "hello"; // 编译错误!
// 但如果不标注类型,TypeScript会进行类型推断
let y = 10; // TypeScript推断为number
y = "hello"; // 编译错误!(类型推断有效)

Python(动态类型 + type hint):

x = 10 # 动态类型,不做检查
x = "hello" # 完全可以
x: int = 10 # type hint,但仅供阅读,不强制
x = "hello" # Python解释器完全允许

Python:只有 None

def greet(name: str | None) -> str:
if name is None:
return "Hello, stranger!"
return f"Hello, {name}!"
print(greet(None)) # 输出: Hello, stranger!
print(greet("Alice")) # 输出: Hello, Alice!

TypeScript:区分 null 和 undefined

function greet(name: string | null | undefined): string {
if (name === null || name === undefined) {
return "Hello, stranger!";
}
return `Hello, ${name}!`;
}
console.log(greet(undefined)); // 输出: Hello, stranger!
console.log(greet(null)); // 输出: Hello, stranger!
console.log(greet("Alice")); // 输出: Hello, Alice!

Python执行模型:

源代码 → 字节码 → Python虚拟机 → 操作系统
(.py) (.pyc)

TypeScript/JavaScript执行模型:

源代码 → 解释器/编译器 → 运行时 → 操作系统
(.ts) (V8/SpiderMonkey)

1.3 为什么Python程序员需要TypeScript

Section titled “1.3 为什么Python程序员需要TypeScript”

如果你计划进入Web开发领域,TypeScript几乎是必备技能:

  1. 前端框架首选:React、Vue 3、Angular 都推荐使用TypeScript
  2. VS Code等工具:微软自家的VS Code本身就是用TypeScript开发的
  3. Node.js后端:越来越多的Node.js项目采用TypeScript以获得更好的可维护性
  4. 全栈统一:前后端都使用TypeScript,类型可以共享
Python概念TypeScript对应备注
deffunction / 箭头函数函数声明方式不同
type hint类型注解TS更强制,编译时检查
classclass语法相似,TS有访问修饰符
Nonenull / undefinedTS区分两者
importimport模块语法几乎相同
isinstance()typeof / instanceof类型检查手段不同
typing 模块内置类型系统功能类似但TS更强大
装饰器 @decorator@decorator语法几乎相同(TS需配置)

根据2024年Stack Overflow调查,TypeScript是第四大最受欢迎的编程语言,而JavaScript是第一。掌握TypeScript能显著提升在前端/全栈领域的竞争力。

对Python开发者来说:

学习难度评估(1-5星,5最难):
Python基础: ★☆☆☆☆
Python进阶: ★★★☆☆
TypeScript基础: ★★☆☆☆
TypeScript类型系统: ★★★★☆
TypeScript泛型: ★★★★★

主要挑战在于:

  • 理解静态类型的好处与约束
  • 掌握泛型(类似Python的泛型但语法不同)
  • 适应编译-运行两步流程

Node.js是运行TypeScript代码的基础环境。

macOS使用Homebrew:

Terminal window
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install node

Windows使用Chocolatey:

Terminal window
choco install nodejs

或直接从官网下载: 访问 https://nodejs.org ,下载LTS(长期支持)版本。

验证安装:

Terminal window
node --version # 显示Node.js版本,如 v20.10.0
npm --version # 显示npm版本,如 10.2.0

全局安装TypeScript编译器:

Terminal window
npm install -g typescript
# 或使用npx直接运行(无需全局安装)
npx tsc --version

验证安装:

Terminal window
tsc --version # 显示TypeScript版本,如 Version 5.3.3
Terminal window
mkdir my-ts-project
cd my-ts-project
npm init -y # 初始化npm项目
npm install typescript --save-dev # 安装TypeScript为开发依赖
npx tsc --init # 生成tsconfig.json
Terminal window
# 使用官方tsconfig模板
npx tsc --init --target es6 --module commonjs --strict true
my-ts-project/
├── node_modules/ # 依赖包
├── src/ # 源代码目录
│ ├── index.ts
│ └── utils.ts
├── dist/ # 编译输出目录
├── package.json # npm配置
├── package-lock.json
└── tsconfig.json # TypeScript配置

这是TypeScript编译器的配置文件,了解各选项非常重要:

{
"compilerOptions": {
/* 基本选项 */
"target": "ES2020", // 编译目标JavaScript版本
"module": "commonjs", // 模块系统
"lib": ["ES2020"], // 包含的库类型定义
/* 输出控制 */
"outDir": "./dist", // 编译输出目录
"rootDir": "./src", // 源代码目录
"removeComments": true, // 移除注释
"noEmitOnError": true, // 错误时不生成文件
/* 类型检查(严格模式) */
"strict": true, // 启用所有严格类型检查
"noImplicitAny": true, // 不允许隐式any类型
"strictNullChecks": true, // 严格null检查
"strictPropertyInitialization": true, // 类属性必须初始化
/* 模块解析 */
"moduleResolution": "node", // Node.js风格解析
"esModuleInterop": true, // 允许默认导入
"resolveJsonModule": true, // 支持JSON模块
/* 实验性选项 */
"experimentalDecorators": true, // 启用装饰器
"emitDecoratorMetadata": true // 装饰器元数据
},
"include": ["src/**/*"], // 包含的文件
"exclude": ["node_modules", "dist"] // 排除的文件
}

VS Code(推荐):

  • 安装 TypeScript Nightly 扩展(微软官方)
  • 安装 ESLint 扩展
  • 快捷键:Cmd/Ctrl + Shift + P → “TypeScript: Select TypeScript Version” → 选择工作区版本

WebStorm/JetBrains:

  • 原生支持TypeScript,配置最少

编译单个文件:

Terminal window
tsc src/index.ts
# 生成 src/index.js

监视模式(文件变化自动编译):

Terminal window
tsc --watch
# 或
tsc -w

编译整个项目:

Terminal window
tsc
# 读取tsconfig.json,编译所有文件

运行编译后的JavaScript:

Terminal window
node dist/index.js

1.5 第一个TypeScript程序 vs 第一个Python程序

Section titled “1.5 第一个TypeScript程序 vs 第一个Python程序”

Python:

print("Hello, Python!")

TypeScript:

console.log("Hello, TypeScript!");

Python:

# Python 3.6+ 变量注解(可选)
name: str = "Alice"
age: int = 30
is_student: bool = False
# 类型可以推断
score = 95.5 # Python不会强制检查

TypeScript:

// 显式类型标注
let name: string = "Alice";
let age: number = 30;
let isStudent: boolean = false;
// 类型推断
let score = 95.5; // TypeScript推断为number
// 编译时检查
name = 123; // 错误!类型不匹配

Python:

def add(a: int, b: int) -> int:
return a + b
def greet(name: str, greeting: str = "Hello") -> str:
return f"{greeting}, {name}!"
# 默认参数
result = add(1, 2) # 3
message = greet("Alice") # "Hello, Alice!"
message2 = greet("Bob", "Hi") # "Hi, Bob!"

TypeScript:

// 箭头函数
const add = (a: number, b: number): number => {
return a + b;
};
// 函数声明
function greet(name: string, greeting: string = "Hello"): string {
return `${greeting}, ${name}!`;
}
// 默认参数
const result = add(1, 2); // 3
const message = greet("Alice"); // "Hello, Alice!"
const message2 = greet("Bob", "Hi"); // "Hi, Bob!"

Python:

age = 20
if age >= 18:
print("成年人")
elif age >= 13:
print("青少年")
else:
print("儿童")

TypeScript:

const age: number = 20;
if (age >= 18) {
console.log("成年人");
} else if (age >= 13) {
console.log("青少年");
} else {
console.log("儿童");
}

Python:

# for循环
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
# 带索引的循环
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")
# while循环
count = 0
while count < 5:
print(count)
count += 1

TypeScript:

// for循环
const fruits: string[] = ["apple", "banana", "cherry"];
for (const fruit of fruits) {
console.log(fruit);
}
// 带索引的循环
fruits.forEach((fruit, i) => {
console.log(`${i}: ${fruit}`);
});
// while循环
let count: number = 0;
while (count < 5) {
console.log(count);
count++;
}

Python:

numbers = [1, 2, 3, 4, 5]
# map
doubled = list(map(lambda x: x * 2, numbers))
# filter
evens = list(filter(lambda x: x % 2 == 0, numbers))
# reduce
from functools import reduce
total = reduce(lambda acc, x: acc + x, numbers, 0)
# 列表推导式
squares = [x**2 for x in numbers]
even_squares = [x**2 for x in numbers if x % 2 == 0]

TypeScript:

const numbers: number[] = [1, 2, 3, 4, 5];
// map
const doubled = numbers.map(x => x * 2);
// filter
const evens = numbers.filter(x => x % 2 === 0);
// reduce
const total = numbers.reduce((acc, x) => acc + x, 0);
// 函数式方法链
const result = numbers
.filter(x => x % 2 === 0)
.map(x => x ** 2)
.reduce((acc, x) => acc + x, 0);
my_python_project/
├── __init__.py
├── main.py
├── utils.py
├── requirements.txt
└── tests/
└── test_utils.py

utils.py:

def calculate_sum(numbers: list[int]) -> int:
"""计算列表所有元素的和"""
return sum(numbers)
def filter_positive(numbers: list[int]) -> list[int]:
"""过滤出正数"""
return [n for n in numbers if n > 0]

main.py:

from utils import calculate_sum, filter_positive
def main():
numbers = [-1, 2, -3, 4, 5, -6]
positives = filter_positive(numbers)
total = calculate_sum(positives)
print(f"正数和: {total}")
if __name__ == "__main__":
main()

运行:python main.py

my_ts_project/
├── src/
│ ├── utils.ts
│ └── main.ts
├── package.json
├── tsconfig.json
└── dist/ (编译输出)

src/utils.ts:

/**
* 计算列表所有元素的和
*/
function calculateSum(numbers: number[]): number {
return numbers.reduce((acc, x) => acc + x, 0);
}
/**
* 过滤出正数
*/
function filterPositive(numbers: number[]): number[] {
return numbers.filter(n => n > 0);
}
export { calculateSum, filterPositive };

src/main.ts:

import { calculateSum, filterPositive } from "./utils";
function main(): void {
const numbers: number[] = [-1, 2, -3, 4, 5, -6];
const positives: number[] = filterPositive(numbers);
const total: number = calculateSum(positives);
console.log(`正数和: ${total}`);
}
main();

编译运行:

Terminal window
tsc
node dist/main.js
// 这段代码在编译时就会报错
const user: { name: string; age: number } = {
name: "Alice",
age: 30
};
user.age = "thirty"; // 编译错误!类型不匹配

Python不会报错,只有运行时才知道有问题。

// 定义数据结构
interface User {
name: string;
age: number;
email?: string; // 可选属性
}
type Point = {
x: number;
y: number;
};
// 编译时检查
function printUser(user: User): void {
console.log(`${user.name}, ${user.age}`);
if (user.email) {
console.log(`Email: ${user.email}`);
}
}
const user: User = { name: "Alice", age: 30 };
printUser(user); // 正常
printUser({ name: "Bob" }); // 编译错误!缺少age属性

Python的等效代码(无编译时检查):

from dataclasses import dataclass
from typing import Optional
@dataclass
class User:
name: str
age: int
email: Optional[str] = None
def print_user(user: User) -> None:
print(f"{user.name}, {user.age}")
if user.email:
print(f"Email: {user.email}")
# Python允许缺少属性,无法在运行前发现
user = User(name="Alice") # 报错:缺少必需参数age

本章从Python开发者的视角认识了TypeScript:

  1. TypeScript是什么:JavaScript的超集,添加了静态类型系统和面向对象特性,需要编译为JavaScript执行

  2. 与Python的区别:

    • TypeScript编译时做类型检查,Python主要靠运行时
    • TypeScript区分null和undefined,Python只有None
    • TypeScript需要两步(编译+运行),Python一步(解释执行)
  3. 为什么学TypeScript:

    • 现代Web开发必备技能
    • 前后端都可使用,类型可共享
    • 在大型项目中比纯JavaScript更易维护
  4. 开发环境:

    • 需要Node.js和npm
    • 全局安装TypeScript编译器tsc
    • 项目需要tsconfig.json配置文件
  5. 第一个程序:

    • Python用def定义函数,TypeScript用function或箭头函数
    • Python用缩进,TypeScript用大括号
    • 模块系统类似(import/export)

在本地环境完成以下任务:

  1. 安装Node.js(如果已安装,跳过此步)
  2. 安装TypeScript编译器
  3. 验证tsc --version输出版本号

创建一个TypeScript程序,实现以下功能:

  • 定义一个函数,接受数字数组,返回所有偶数的和
  • 在main函数中测试这个函数
  • 编译并运行
  1. 在tsconfig.json中将strict设为false
  2. 尝试编写一段类型不匹配的代码
  3. 观察编译结果
  4. 将strict改回true,再次编译观察差异

访问 TypeScript官方文档,阅读”Getting Started”部分,了解最新的TypeScript特性。



下一章我们将深入学习TypeScript的类型系统,理解静态类型如何让代码更健壮,以及Python的type hint与TypeScript类型注解的异同。