TypeScript 与 JavaScript 语法速览(Python 对照)

这篇笔记写给已掌握 Python、现在要读和写 TypeScript 代码的开发者。它不是从零教编程,而是帮你把 Python 的语法直觉翻译成 JS/TS 的等价写法——聚焦那些看起来像但行为不同、或者Python 里根本没有的语言机制。

TypeScript 是 JavaScript 的超集——所有 JS 语法在 TS 中完全有效。所以这篇笔记混用 JS 和 TS 示例:JS 部分对应运行时语法,TS 类型注解(冒号后面的东西)在后续章节展开。


1. 变量声明:const / let / var vs Python 赋值

Python 的赋值即声明;JS/TS 必须先声明再使用。

# Python:赋值就是声明
x = 42
x = "hello"  # 随时可以变类型
// TS:const(不可重新赋值)vs let(可重新赋值)
const x = 42;        // 不可 re-assign
// x = 43;           // 编译错误
let y = 42;          // 可重新赋值
y = 43;
 
// 类型注解(可选,靠推断)
const name: string = "Alice";
let age: number = 30;
 
// var(有作用域陷阱,永远不用)
var z = 42;          // 函数作用域,不是块作用域
关键词可重新赋值?作用域与 Python 对比
const块级 {}类似赋值后永不改的变量
let块级 {}最接近 Python 的普通变量
var函数级不用——提升行为是陷阱

Python 的变量可以随时改类型;TS 的变量一旦推断出类型就固定了。const 只是禁止 = 重新赋值,不禁止 .push() 修改数组内容。


2. 函数:五种写法 vs Python 的 def / lambda

# Python:两种函数形式
def add(a, b):
    return a + b
 
add = lambda a, b: a + b  # 只能单表达式,不能有语句
// TS:五种函数形式
 
// 1. 函数声明(会被提升)
function add(a: number, b: number): number {
  return a + b;
}
 
// 2. 函数表达式
const add = function(a: number, b: number): number {
  return a + b;
};
 
// 3. 箭头函数(最常用,没有自己的 this)
const add = (a: number, b: number): number => a + b;
 
// 4. 箭头函数 + 语句体
const add = (a: number, b: number): number => {
  const result = a + b;
  return result;
};
 
// 5. 方法简写(对象内)
const obj = {
  add(a: number, b: number): number {
    return a + b;
  },
};
维度Python defPython lambdaTS 箭头函数TS function
可含语句
this 绑定❌ 显式 self❌(词法 this✅ 动态 this
可做回调可以常规用法✅ 最常用可以

习惯转换:Python 里你用 def 定义一切;TS 里回调优先箭头函数items.map(x => x * 2)),顶层逻辑用 function 或箭头函数均可。


3. 对象与解构 vs Python 的 dict

JS 的对象是核心数据结构——它同时承担 Python 里 dictdataclassNamedTuple 的角色。

# Python
user = {"name": "Alice", "age": 30}
name = user["name"]
age = user["age"]
 
# Python 3.10+ 结构匹配(类似但不等于解构)
match user:
    case {"name": n, "age": a}:
        print(n, a)
// TS:对象字面量 + 解构
const user = { name: "Alice", age: 30 };
 
// 解构(destructuring)——极常用
const { name, age } = user;
console.log(name, age); // Alice 30
 
// 重命名 + 默认值
const { name: userName, email = "[email protected]" } = user;
 
// 函数参数解构
function greet({ name, age }: { name: string; age: number }) {
  return `${name} is ${age}`;
}
 
// 展开(spread)——创建浅拷贝 + 覆盖
const updated = { ...user, age: 31 };
// { name: "Alice", age: 31 }
操作PythonTS/JS
访问属性d["key"]d.key(dataclass)obj.keyobj["key"]
解构match case 或手动拆const { a, b } = obj
合并{**d1, **d2}{ ...obj1, ...obj2 }
判断键存在"key" in d"key" in obj

4. this vs Python 的 self

这是 Python 开发者最容易踩的坑。

# Python:self 是显式参数,绑定由调用方式决定
class Button:
    def __init__(self, text):
        self.text = text
 
    def handle(self):
        print(self.text)   # self 永远指向接收者
 
btn = Button("Click")
btn.handle()               # self = btn
cb = btn.handle
cb()                       # Python 3 里 self 仍是 btn(绑定方法)
// TS/JS:this 是隐式的,由"谁调用"决定
class Button {
  text: string;
  constructor(text: string) {
    this.text = text;
  }
 
  handle() {
    console.log(this.text);
  }
}
 
const btn = new Button("Click");
btn.handle();          // this = btn
 
const cb = btn.handle;
cb();                  // this = undefined(严格模式)或 window!
 
// 修复方式:箭头函数(词法 this)
class ButtonFixed {
  text: string;
  constructor(text: string) {
    this.text = text;
  }
 
  handle = () => {
    console.log(this.text); // 箭头函数不绑定自己的 this
  };
}
维度PythonTS/JS
声明显式 self 参数隐式 this
绑定时机方法对象创建时(描述符协议)调用时
回调安全性✅ 绑定方法自动带 self❌ 裸函数丢失 this
修复手段不需要箭头函数 / .bind()

TS 里回调函数优先箭头函数——不是为了简洁,是为了 this 不会丢。


5. 相等性:=== vs == vs Python

# Python:== 是值相等,类型不匹配直接返回 False
0 == "0"        # False
0 == False      # False(Python 3)
[] == False     # False
None == False   # False
// JS:== 会做类型转换(永远不要用)
0 == "0";        // true  (wtf — 字符串被转成数字)
0 == false;      // true  (wtf — 布尔被转成数字 0)
"" == false;     // true  (wtf — 两者都被转为 0)
null == undefined; // true
 
// === 不做类型转换(永远用这个)
0 === "0";       // false
0 === false;     // false
null === undefined; // false
运算符PythonTS/JS
宽松比较(无)==(做类型转换,别用)
严格比较=====(值 + 类型都相等)
不等!=!==(严格不等)

忘记 JS 有 ==!=,只用 ===!==


6. 空值:null vs undefined vs Python None

# Python:只有一个空值
x = None
name = None
 
# 判断空
if x is None:
    print("空")
// TS:两个空值,语义不同
let x: null = null;          // 有意设为"没有值"
let y: undefined = undefined; // 变量声明了但未赋值
 
// 不赋值的变量默认是 undefined
let z: string;               // z 的值是 undefined
 
// 判断空
if (x === null) { /* ... */ }
if (y === undefined) { /* ... */ }
 
// 判断"非空"(排除 null 和 undefined 两者)
if (value != null) { /* ... */ } // 这是 == 唯一被容忍的用法
 
// ?? 空值合并(null/undefined 时用默认值)
const name = input ?? "Anonymous"; // null / undefined → "Anonymous"
 
// ?. 可选链(null/undefined 时不报错,返回 undefined)
const city = user?.address?.city;  // 任一环节为 null/undefined → undefined
概念PythonTS/JS
空值None(一个)null + undefined(两个)
默认值x or default(但不安全)x ?? default
安全访问getattr(obj, "attr", None)obj?.attr

Python 直觉迁移:把 null 看作 Noneundefined 是 JS 特有的——大多数时候你只需要检查”非 null 且非 undefined”,用 != null??


7. 模板字面量 vs f-string

# Python
name = "Alice"
s = f"Hello, {name}!"
multi = f"""
  你好,{name}
  欢迎回来
"""
// TS:模板字面量(反引号,不是引号)
const name = "Alice";
const s = `Hello, ${name}!`;     // 注意:反引号
 
// 多行(保留缩进和换行,与 Python f-string 行为不同)
const multi = `
  你好,${name}
  欢迎回来
`;
 
// 带标签的模板(高级用法)
const raw = String.raw`C:\Users\${name}\docs`; // 反斜杠不转义
维度Python f-stringTS 模板字面量
分隔符f"..."f'...'`...`(反引号)
插值{expr}${expr}
多行"""...""" 自动去缩进严格保留所有空白

8. 迭代:for...of / .map() / .forEach() vs Python

# Python
items = [1, 2, 3]
 
# 遍历值
for item in items:
    print(item)
 
# 生成新列表
doubled = [x * 2 for x in items]
 
# 带索引
for i, item in enumerate(items):
    print(i, item)
// TS:四种主流迭代方式
 
const items = [1, 2, 3];
 
// 1. for...of(遍历值——最接近 Python for...in)
for (const item of items) {
  console.log(item);
}
 
// 2. .map()(生成新数组——最常用)
const doubled = items.map(x => x * 2);
 
// 3. .forEach()(纯副作用,不返回值)
items.forEach((item, index) => {
  console.log(index, item);
});
 
// 4. for...in(遍历键/索引——通常不是你想要的)
for (const index in items) {  // index 是 "0", "1", "2"(字符串!)
  console.log(index, items[index]);
}
需求PythonTS/JS
遍历值for x in itemsfor (const x of items)
生成新列表[f(x) for x in items]items.map(x => f(x))
带索引遍历enumerate(items).forEach((x, i) => ...)
过滤[x for x in items if p(x)]items.filter(x => p(x))

for...in 在 JS 里遍历的是键名(字符串),不是值。除非你明确需要对象的键,否则用 for...of


9. 模块导入导出 vs Python

# Python
import os
from collections import defaultdict
from .utils import helper    # 相对导入
import numpy as np
// TS:三种导入风格混合(取决于模块系统和打包器)
 
// 1. ESM(现代标准,Node 23+ / Vite 默认)
import fs from "node:fs";              // 默认导入
import { readFile } from "node:fs";    // 命名导入
import * as fs from "node:fs";         // 命名空间导入
import type { User } from "./types";   // 仅类型导入(编译后消失)
 
// 2. CJS(旧 Node 代码,正在消退)
const fs = require("fs");
 
// 导出
export default User;                   // 默认导出(一个文件一个)
export { User, createUser };           // 命名导出(多个)
export type { User };                  // 仅类型导出
操作PythonTS/JS (ESM)
默认导入❌ 不区分import X from "./x"
命名导入from x import a, bimport { a, b } from "./x"
全部导入import ximport * as x from "./x"
重命名import numpy as npimport { longName as L } from "./x"
类型导入(不需要区分)import type { User } from "./x"

10. Spread / Rest 运算符 ...

# Python:* 和 ** 打包/解包
def f(a, b, c):
    return a + b + c
 
args = [1, 2, 3]
f(*args)                    # 解包列表为位置参数
 
def g(**kwargs):
    print(kwargs)
 
g(name="Alice", age=30)     # 打包关键字参数为 dict
// TS:... 统一处理数组和对象的展开/收集
 
// Rest:收集剩余参数
function f(a: number, ...rest: number[]): number {
  return a + rest.reduce((sum, n) => sum + n, 0);
}
f(1, 2, 3, 4); // a=1, rest=[2,3,4]
 
// Spread:展开
const nums = [1, 2, 3];
const moreNums = [...nums, 4, 5];  // [1, 2, 3, 4, 5]
 
// 对象展开(没有 Python 对应)
const defaults = { theme: "light", lang: "zh" };
const overrides = { lang: "en" };
const config = { ...defaults, ...overrides }; // { theme: "light", lang: "en" }

... 在函数参数位置是 Rest(收集),在调用/赋值位置是 Spread(展开)。


11. Truthy/Falsy:JS 的隐式布尔转换

# Python:只有少数值是 falsy
bool(None)    # False
bool(0)       # False
bool("")      # False
bool([])      # False
bool({})      # False
# 其他都是 truthy
// JS/TS:falsy 值的列表更长且包含陷阱
// Falsy 值:false, 0, -0, 0n, "", null, undefined, NaN
// 其他都是 truthy(包括空数组和空对象!)
 
Boolean(null);       // false
Boolean(undefined);  // false
Boolean(0);          // false
Boolean("");         // false
Boolean(NaN);        // false
Boolean([]);         // true ⚠️ 空数组是 truthy!
Boolean({});         // true ⚠️ 空对象是 truthy!
Boolean(" ");        // true  ⚠️ 空白字符串是 truthy!
 
// 陷阱:判断数组是否非空
if (arr.length > 0) { } // 明确
if (arr) { }            // 空数组也是 true

习惯转换:不要用 if (x) 来判断数组/对象是否非空——JS 的空数组和空对象是 truthy。用 x.length > 0Object.keys(x).length > 0


关联