1. Basic Types
TypeScript's basic types are similar to those in languages you're familiar with, but all use lowercase:
// 显式类型注解
let name: string = "TypeScript";
let age: number = 12; // 没有 int/float 之分,统一为 number
let isDone: boolean = false;
let big: bigint = 100n; // 大整数,注意后缀 n
let id: symbol = Symbol("id"); // 唯一标识符
💡 Type Inference: TypeScript can automatically infer variable types — you don't always need to write annotations manually.
// 类型推断 —— 编译器自动推导类型
let city = "Shanghai"; // 推断为 string
let count = 42; // 推断为 number
let active = true; // 推断为 boolean
// const 声明会推断为字面量类型
const PI = 3.14; // 推断为 3.14,不是 number
const lang = "TS"; // 推断为 "TS",不是 string
🔄 Difference from Java
TS's type system is structural typing, not nominal typing. Two types with the same structure are compatible without explicitly declaring implements. This is called "duck typing" — if it walks like a duck and quacks like a duck, then it's a duck.
2. Special Types
// any —— 逃生舱口,关闭类型检查(尽量避免!)
let anything: any = 42;
anything = "hello"; // 不报错
anything.foo.bar; // 不报错,但运行时可能崩溃
// unknown —— 安全的 any,使用前必须检查类型
let data: unknown = fetchSomething();
// data.toString(); // ❌ 编译错误!不能直接使用
if (typeof data === "string") {
data.toUpperCase(); // ✅ 类型收窄后可以使用
}
// void —— 函数无返回值
function log(msg: string): void {
console.log(msg);
}
// null 和 undefined —— 两个独立的类型
let n: null = null;
let u: undefined = undefined;
// never —— 永远不会有值的类型
function throwError(msg: string): never {
throw new Error(msg); // 函数永远不会正常返回
}
function infiniteLoop(): never {
while (true) {} // 永远不会结束
}
💡 Rule of thumb: Use unknown instead of any. unknown forces you to perform type checks before use, making it safer.
3. Literal Types and Union Types
Literal Types
TypeScript allows specific values to be used as types — something rarely seen in other languages:
let yes: true = true;
// yes = false; // ❌ 类型 'false' 不能赋给类型 'true'
let httpOk: 200 = 200;
let greeting: "hello" = "hello";
Union Types
Use | to combine multiple types, meaning "one of":
// 经典用法:限定有效值的范围
type Direction = "up" | "down" | "left" | "right";
function move(dir: Direction) {
console.log(`Moving ${dir}`);
}
move("up"); // ✅
// move("forward"); // ❌ 类型 '"forward"' 不能赋给类型 'Direction'
// 混合类型联合
type ID = string | number;
let userId: ID = "abc123";
userId = 42; // ✅ 也合法
Discriminated Unions
Distinguish between different types in a union using a shared "tag" field — an extremely common pattern in TS:
type Shape =
| { kind: "circle"; radius: number }
| { kind: "rectangle"; width: number; height: number };
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "rectangle":
return shape.width * shape.height; // TS 在这里知道有 width 和 height
}
}
4. Intersection Types
Use & to merge multiple types — the resulting type includes all properties:
interface HasName {
name: string;
}
interface HasAge {
age: number;
}
// 交叉类型:同时拥有 name 和 age
type Person = HasName & HasAge;
const alice: Person = {
name: "Alice",
age: 30,
};
// 实用场景:给已有类型添加字段
type Timestamped<T> = T & { createdAt: Date; updatedAt: Date };
type TimestampedPerson = Timestamped<Person>;
// 等价于 { name: string; age: number; createdAt: Date; updatedAt: Date }
💡 Union | means "or" — the value is one of the types; Intersection & means "and" — the value satisfies all types simultaneously.
5. Type Assertions and Non-null Assertions
Type Assertion
When you know better than the compiler about a value's type, use as to tell the compiler:
// DOM 操作是最常见的场景
const el = document.getElementById("app") as HTMLDivElement;
el.style.color = "red"; // 不会报错,因为你断言了它是 HTMLDivElement
// 也可以用尖括号语法(在 JSX/TSX 中不可用)
const el2 = <HTMLDivElement>document.getElementById("app");
// 双重断言 —— 在两个不相关的类型间转换(谨慎使用)
const value = "hello" as unknown as number;
Non-null Assertion
Use the ! postfix to tell the compiler "this value is definitely not null/undefined":
// getElementById 返回 HTMLElement | null
const el = document.getElementById("app")!; // 断言不为 null
el.style.color = "blue";
// 等价于
const el2 = document.getElementById("app");
if (el2 === null) throw new Error("Element not found");
el2.style.color = "blue";
⚠️ Both type assertions and non-null assertions bypass type checking. If the assertion is wrong, it will still crash at runtime. Prefer using type guards for safe type narrowing.
6. Type Guards
Type guards let TypeScript automatically narrow types in conditional branches, without manual assertions:
typeof Guard
function padLeft(value: string | number): string {
if (typeof value === "number") {
return " ".repeat(value); // 这里 value 是 number
}
return value; // 这里 value 是 string
}
instanceof Guard
function formatDate(input: string | Date): string {
if (input instanceof Date) {
return input.toISOString(); // input 是 Date
}
return new Date(input).toISOString(); // input 是 string
}
in Guard
interface Fish { swim(): void; }
interface Bird { fly(): void; }
function move(animal: Fish | Bird) {
if ("swim" in animal) {
animal.swim(); // animal 是 Fish
} else {
animal.fly(); // animal 是 Bird
}
}
Custom Type Guard Functions
// 返回类型 'x is Type' 是关键
function isString(value: unknown): value is string {
return typeof value === "string";
}
function process(input: unknown) {
if (isString(input)) {
console.log(input.toUpperCase()); // TS 知道 input 是 string
}
}
// 实际场景:验证 API 响应
interface ApiResponse {
data: unknown;
status: number;
}
interface User {
id: number;
name: string;
email: string;
}
function isUser(obj: unknown): obj is User {
return (
typeof obj === "object" &&
obj !== null &&
"id" in obj &&
"name" in obj &&
"email" in obj
);
}
7. TypeScript-Specific Operators
These operators come from JavaScript (ES2020+), but are especially powerful when combined with TypeScript's type system:
?? Nullish Coalescing
// ?? 只在左侧为 null 或 undefined 时取右侧值
const port = config.port ?? 3000;
// 区别于 ||:|| 在左侧为任何 falsy 值时取右侧
const count1 = 0 || 10; // 10 (0 是 falsy)
const count2 = 0 ?? 10; // 0 (0 不是 null/undefined)
const name1 = "" || "默认"; // "默认"(空字符串是 falsy)
const name2 = "" ?? "默认"; // "" (空字符串不是 null/undefined)
?. Optional Chaining
interface Company {
name: string;
address?: {
city?: string;
street?: string;
};
}
function getCity(company: Company): string | undefined {
// 无需层层判断 null —— 任何一步为 null/undefined 就返回 undefined
return company.address?.city;
}
// 也适用于方法调用和数组索引
const result = obj.method?.(); // 方法可能不存在
const first = arr?.[0]; // 数组可能是 undefined
const value = map.get?.("key"); // get 可能不存在
=== vs == (Strict Equality)
// === 严格相等:不做类型转换(推荐始终使用)
0 === "" // false
0 === false // false
null === undefined // false
// == 宽松相等:会做类型转换(避免使用)
0 == "" // true 😱
0 == false // true 😱
null == undefined // true
// TypeScript 在 strict 模式下对 == null 有特殊处理
// value == null 等价于 value === null || value === undefined
function example(value: string | null | undefined) {
if (value == null) {
// 这里 value 是 null | undefined
}
}
🔄 Difference from Python
Python's type hints are ignored at runtime (def foo(x: int) won't error when passed a string), while TypeScript's types are enforced at compile time. TS's ?. is syntactic sugar that Python doesn't have; Python requires getattr(obj, 'attr', None) or chained if checks.
📋 Chapter Summary
Type Inference is Smart
In most cases, you don't need to manually write type annotations — TS will infer them automatically. Add annotations for function parameters and complex scenarios.
Structural Type System
TS uses duck typing — it only checks structure, not names. Fundamentally different from Java/C++'s nominal type systems.
Union Types are Core
Union types | combined with discriminated unions and type guards are the most common type modeling approach in TS.
unknown Over any
When you need "any type", use unknown — it requires type checks before use, preventing runtime errors.
Type Guards > Type Assertions
Prefer typeof, instanceof, in type guards for safe type narrowing over as assertions.
Master ?. and ??
Optional chaining ?. and nullish coalescing ?? greatly simplify null/undefined handling, and work even better with the type system.