一篇文章快速入门TypeScript基础语法
TypeScript 基础入门教程
1. TypeScript 基础介绍
TypeScript 作为 JavaScript 的超集,通过静态类型检查提升了代码的可靠性和可维护性。
1.1 什么是 TypeScript?
TypeScript 是微软开发的 JavaScript 超集,它在 JS 基础上添加了静态类型系统,使代码更健壮、更易维护。TypeScript 通过编译时类型检查,能够在开发阶段就发现潜在的类型错误。
TypeScript在线编程网站:https://www.typescriptlang.org/play/
1.2 TypeScript 与 JavaScript 的区别
TypeScript 和 JavaScript 的主要区别在于类型系统的实现方式。TypeScript 在开发阶段进行静态类型检查,而 JavaScript 则是动态类型语言。
特性 | JavaScript | TypeScript |
---|---|---|
类型检查 | 动态类型(运行时检查) | 静态类型(编译时检查) |
编译 | 直接运行 | 需编译成 JS |
兼容性 | 所有浏览器支持 | 最终编译为 JS |
面向对象 | 支持但不强制 | 更完善的 OOP 支持 |
工具支持 | 一般 | 强大的 IDE 提示 |
2. TypeScript 基础类型
理解 TypeScript 的类型系统是掌握该语言的基础。
2.1 JavaScript 的 7 种基本类型
JavaScript 原生支持的七种基本数据类型在 TypeScript 中都有对应的类型注解。
let str: string = "hello"; // 字符串
let num: number = 123; // 数字
let bool: boolean = true; // 布尔值
let undef: undefined = undefined; // undefined
let nul: null = null; // null
let sym: symbol = Symbol("key"); // Symbol
let big: bigint = 100n; // 大整数
2.2 TypeScript 新增类型
除了 JavaScript 的基础类型外,TypeScript 还引入了一些特殊类型来增强类型系统的表达能力。
let arr: number[] = [1, 2, 3]; // 数字数组 → [1, 2, 3]
let tuple: [string, number] = ["a", 1]; // 元组 → ["a", 1]
let anyType: any = "anything"; // 任意类型 → 可以赋值为任何值
let voidType: void = undefined; // 无返回值 → undefined
let neverType: never = (() => { throw Error() })(); // 永不返回 → 函数抛出错误
3. 枚举类型与表驱动法
枚举和表驱动法是 TypeScript 中组织代码的两种有效方式。
3.1 枚举(Enum)
枚举类型允许开发者定义一组命名的常量,提高代码的可读性和可维护性。
// 定义一个简单的方向枚举
enum Direction {Up = "向上",Down = "向下",Left = "向左",Right = "向右"
}// 使用枚举
let move: Direction = Direction.Up;
console.log(move); // 输出:"向上"
3.2 表驱动法
表驱动法是一种替代复杂条件判断的编程模式,通过将逻辑映射到数据结构中来简化代码。
// 用对象实现简单的命令处理
const commandHandler = {start: () => console.log("系统启动中..."),stop: () => console.log("系统关闭中..."),restart: () => console.log("系统重启中...")
};// 根据输入命令执行对应操作
function executeCommand(cmd: "start" | "stop" | "restart") {commandHandler[cmd](); // 像查字典一样执行对应函数
}executeCommand("start"); // 输出:"系统启动中..."
4. interface 接口与 type 类型别名
接口和类型别名是 TypeScript 中定义复杂类型的两种主要方式。
4.1 interface(可扩展)
接口是定义对象结构的强大工具,支持继承和扩展。
// 基础用法
interface User {name: string; // 必填属性age?: number; // 可选属性readonly id: number; // 只读属性
}let user: User = { name: "Alice", id: 123
}; // 合法,age可选// 接口扩展(继承)
interface Admin extends User {permissions: string[];
}const admin: Admin = {name: "Bob",id: 456,permissions: ["create", "delete"]
};
4.2 type(适合联合类型)
类型别名更适合定义联合类型或创建复杂类型的简写形式。
// 定义联合类型
type ID = string | number;
let userId: ID = "user123"; // 可以是字符串
let postId: ID = 456; // 也可以是数字// 定义对象类型别名
type Point = { x: number;y: number;
};// 使用类型别名
let center: Point = { x: 0,y: 0
};// 定义函数类型
type Callback = (data: string) => void;
const log: Callback = (msg) => console.log(msg);
5. 交叉类型与联合类型
5.1 交叉类型(&)
交叉类型将多个类型合并为一个类型:
type Person = {name: string;
};type Employee = {id: number;department: string;
};// 合并两个类型
type Staff = Person & Employee;const john: Staff = {name: "John",id: 1001,department: "IT"
};// 合并接口和类型别名
type Contact = {email: string;
} & Person;const alice: Contact = {name: "Alice",email: "alice@example.com"
};
5.2 联合类型(|)
联合类型表示一个值可以是多种类型之一:
// 基础用法
function printId(id: number | string) {console.log(`ID: ${id}`);
}printId(101); // 数字ID
printId("abc123"); // 字符串ID// 配合类型检查
function formatValue(value: string | number) {if (typeof value === "string") {return value.toUpperCase();}return value.toFixed(2);
}// 对象类型联合
type Circle = {kind: "circle";radius: number;
};type Square = {kind: "square";sideLength: number;
};type Shape = Circle | Square;function getArea(shape: Shape) {switch (shape.kind) {case "circle":return Math.PI * shape.radius ** 2;case "square":return shape.sideLength ** 2;}
}
5.3 交叉类型(&)与联合类型(|)核心区别
// 交叉类型(基本类型)
type A = string & number; // never(互斥)
type B = 'a' & string; // 'a'(子类型兼容)// 联合类型(基本类型)
type C = string | number; // 字符串或数字
type D = 'a' | 'b'; // 字面量联合// 交叉类型(对象类型)
type Person = { name: string };
type Employee = { id: number };
type Staff = Person & Employee;
// { name: string; id: number }(属性合并)// 联合类型(对象类型)
type Cat = { purr(): void };
type Dog = { bark(): void };
type Pet = Cat | Dog;
// 使用时只能访问共有属性(如无共有属性则只能类型保护后访问)
“基本看兼容,对象做合并”
- 基本类型:交叉检查兼容性 → 不兼容则
never
- 对象类型:交叉合并属性 → 联合限制访问
6. 类型断言与类型保护
类型断言是告诉编译器某个值的具体类型的方式,类似于其他语言中的类型转换,但在 TypeScript 中它不会影响运行时的实际值。
// 基本用法
let someValue: any = "this is a string";
let strLength1: number = (someValue as string).length;
let strLength2: number = (<string>someValue).length; // 另一种语法// 实际应用场景
const canvas = document.getElementById('myCanvas') as HTMLCanvasElement;
const ctx = canvas.getContext('2d'); // 现在可以安全地使用canvas方法// 注意:断言不是类型转换,只是让编译器信任开发者的判断
let num = "123" as any as number; // 双重断言(不推荐)
7. 类型保护(typeof/in)
7.1 使用 typeof 的类型保护
typeof 类型保护用于区分基本类型,是 JavaScript 中 typeof 运算符的类型安全版本。
// 基本用法
function printValue(val: string | number | boolean) {if (typeof val === "string") {console.log(val.toUpperCase()); // val 被识别为 string} else if (typeof val === "number") {console.log(val.toFixed(2)); // val 被识别为 number} else {console.log(`布尔值: ${val}`); // val 被识别为 boolean}
}// 实际应用
function processInput(input: string | number[]) {if (typeof input === "string") {return input.trim().split(' ');} else {return input.map(num => num * 2);}
}// 注意事项
let value: string | null = getValue();
if (typeof value === "string") {console.log(value.length); // 安全,因为排除了null
}
typeof 类型保护只能识别 “string”、“number”、“boolean”、“symbol”、“undefined”、“object” 和 “function” 这些基本类型。
7.2 使用 in 操作符的类型保护
in 操作符类型保护通过检查对象是否包含特定属性来缩小类型范围。
interface Dog {bark(): void;walk(): void;
}interface Cat {meow(): void;walk(): void;
}function handlePet(pet: Dog | Cat) {if ('bark' in pet) {pet.bark(); // 这里 pet 被识别为 Dog} else {pet.meow(); // 这里 pet 被识别为 Cat}pet.walk(); // 公共方法可以直接调用
}// 使用示例
const myDog: Dog = {bark: () => console.log("Woof!"),walk: () => console.log("Dog walking")
};const myCat: Cat = {meow: () => console.log("Meow~"),walk: () => console.log("Cat walking")
};handlePet(myDog); // 输出: Woof! Dog walking
handlePet(myCat); // 输出: Meow~ Cat walking
8. 索引类型与映射类型
索引类型和映射类型是 TypeScript 高级类型系统的核心组成部分。
8.1 索引类型
索引类型允许开发者通过键名动态访问对象属性,同时保持类型安全。
// 定义一个用户接口
interface User {id: number;name: string;email: string;age?: number; // 可选属性
}// 获取User接口的所有键名组成的联合类型
type UserKeys = keyof User;
// 等价于 "id" | "name" | "email" | "age"// 使用示例
function getUserProperty(user: User, key: UserKeys) {return user[key]; // 类型安全地访问属性
}const user = { id: 1, name: "Alice", email: "alice@example.com" };
console.log(getUserProperty(user, "name")); // 输出 "Alice"
// getUserProperty(user, "address"); // 错误:参数类型不匹配
8.2 映射类型
映射类型允许开发者基于现有类型创建新类型,批量修改属性特性。
// 基础映射类型示例
type Optional<T> = {[P in keyof T]?: T[P]; // 将所有属性变为可选
};type UserOptional = Optional<User>;
/* 等价于:
{id?: number;name?: string;email?: string;age?: number;
}
*/// 内置Readonly的实现
type MyReadonly<T> = {readonly [P in keyof T]: T[P];
};// 使用示例
const readOnlyUser: MyReadonly<User> = {id: 1,name: "Bob",email: "bob@example.com"
};
// readOnlyUser.name = "Alice"; // 错误:只读属性不可修改// 更复杂的映射类型:给所有属性添加null类型
type Nullable<T> = {[P in keyof T]: T[P] | null;
};
9. 泛型 T
泛型是 TypeScript 中创建可重用组件的重要工具,它允许开发者编写可以适用于多种类型的代码。
// 基本泛型函数
function identity<T>(arg: T): T {return arg;
}// 使用示例
let str = identity<string>("hello"); // str 类型为 string
let num = identity<number>(42); // num 类型为 number
let bool = identity<boolean>(true); // bool 类型为 boolean// 类型推断
let inferredStr = identity("hello"); // 编译器自动推断 T 为 string
let inferredNum = identity(42); // 编译器自动推断 T 为 number// 泛型接口定义
interface KeyValuePair<K, V> {key: K;value: V;
}// 使用示例
let pair1: KeyValuePair<string, number> = {key: "age",value: 30
};let pair2: KeyValuePair<number, boolean> = {key: 1,value: true
};
10. 条件类型与工具类型
条件类型和工具类型极大地扩展了 TypeScript 类型系统的表达能力。
10.1 条件类型(extends ? :)
条件类型根据条件表达式选择不同的类型分支,实现动态类型推导。
interface Animal {name: string;
}interface Dog extends Animal { // Dog 继承 Animal 的所有属性breed: string;
}function logLength<T extends { length: number }>(arg: T) {console.log(arg.length); // 确保参数有 length 属性
}type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<123>; // false
10.2 内置工具类型
TypeScript 提供了一系列内置工具类型来简化常见类型转换操作。
interface User {name: string;age: number;email?: string;
}// 1. Partial: 所有属性变为可选
type PartialUser = Partial<User>;
// 等价于 { name?: string; age?: number; email?: string }// 2. Pick: 选择部分属性
type PickUser = Pick<User, "name" | "email">;
// 等价于 { name: string; email?: string }// 3. Omit: 排除部分属性
type OmitUser = Omit<User, "age">;
// 等价于 { name: string; email?: string }// 4. Exclude: 从联合类型中排除特定类型
type T1 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number// 5. NonNullable: 排除 null 和 undefined
type T3 = NonNullable<string | number | null | undefined>; // string | number// 6. Readonly: 使所有属性变为只读
type ReadonlyUser = Readonly<User>;
// 等价于 { readonly name: string; readonly age: number; readonly email?: string }// 7. Extract: 从联合类型中提取特定类型
type T4 = Extract<"a" | "b" | "c", "a" | "d">; // "a"
type T5 = Extract<string | number | (() => void), Function>; // () => void// 8. Record: 构造键值类型明确的对象类型
type UserMap = Record<"admin" | "guest", User>;
// 等价于 { admin: User; guest: User }// 9. ReturnType: 获取函数返回类型
type FnReturn = ReturnType<() => string>; // string// 10. Parameters: 获取函数参数类型
type FnParams = Parameters<(name: string, age: number) => void>; // [string, number]