sim-ts
你的观察很敏锐!Python 的类型注解(Type Hints)和 TypeScript 的类型语法确实非常相似,这是因为它们都受到了现代静态类型语言(如 Java、C#、OCaml、Haskell)的影响,并且都致力于在动态语言的基础上增加可选的静态类型检查。
相似点一览
| 特性 | Python | TypeScript |
|---|---|---|
| 变量类型注解 | name: str | name: string |
| 函数参数与返回值 | def f(x: int) -> str: | function f(x: number): string |
| 可选/联合类型 | str | None 或 Optional[str] | string | null 或 string | undefined |
| 泛型 | List[T]、Dict[K, V] | Array<T>、Map<K, V> |
| 类型别名 | UserId = int | type UserId = number |
| 接口/协议 | Protocol(typing 模块) | interface |
| 字面量类型 | Literal["foo"] | "foo" |
| 类型守卫 | isinstance(x, str) | typeof x === "string" |
为什么这么像?
-
共同的语法源头
两者都采用变量: 类型这种后缀类型注解的方式,和 C/C++/Java 的类型 变量前缀风格不同。这种后缀风格其实在 Pascal、Ada、Rust、Scala 中很常见。Python 从 2006 年的 PEP 3107 就开始支持函数注解(当时没固定语义),后来 2014 年的 PEP 484(类型提示)正式确立了语法;TypeScript 2012 年诞生时也选择了这种风格。 -
目标一致:动态语言的静态检查
Python 和 TypeScript 都是在动态类型基础上提供可选的静态类型系统,因此都需要:- 不破坏运行时行为(Python 的类型注解不强制,TS 的类型会在编译后擦除)
- 语法尽量简洁、直观,不喧宾夺主
- 支持渐进式迁移(旧代码可以不写类型)
-
互相借鉴
虽然两者独立发展,但开发者社区经常互相参考。Python 3.10 引入的|联合类型(int | None)就和 TypeScript 的|非常像。TypeScript 的as类型断言也在 Python 的typing.cast()中有对应。
核心区别(不只是语法)
| 方面 | Python | TypeScript |
|---|---|---|
| 类型检查时机 | 需要第三方工具(mypy、pyright)在开发时或 CI 阶段检查 | 集成在编译器(tsc)中,编译时检查 |
| 运行时行为 | 类型注解完全保留,可通过 __annotations__ 访问,但不会自动检查 | 类型在编译后完全擦除,不产生运行时开销 |
| 泛型实现 | 基于类型擦除(类似 Java),但使用 TypeVar | 基于结构类型系统(structural typing),也有泛型擦除 |
| 空值处理 | None 默认可以赋给任何类型,除非开启 strictOptional 或使用 Optional | 默认严格,string 不能赋 null/undefined,除非配置 strictNullChecks |
简单示例对比
Python:
def greet(name: str | None) -> str:
if name is None:
return "Hello, stranger"
return f"Hello, {name}"
TypeScript:
function greet(name: string | null): string {
if (name === null) {
return "Hello, stranger";
}
return `Hello, ${name}`;
}
小结
你的感觉完全正确 —— 它们很像,因为:
- 都选择了后缀类型注解语法(
变量: 类型) - 都支持联合类型、泛型、类型别名等现代类型特性
- 都致力于在动态语言中提供渐进式的静态类型检查体验
虽然语法相似,但背后的类型系统哲学略有不同(Python 是名义类型 + 可选鸭子类型,TypeScript 是结构化类型),不过日常写起来的感觉确实十分接近。如果你同时写 Python 和 TypeScript,你会发现类型注解几乎可以“无缝切换” 😄