为什么学习 TypeScript?
TypeScript 已经成为现代前端开发的标配。据 2023 年 State of JS 调查,超过 80% 的开发者正在使用或计划使用 TypeScript。
TypeScript 的优势
- 类型安全:在编译时发现错误
- 更好的 IDE 支持:智能提示、自动补全
- 代码可维护性:类型即文档
- 大型项目必备:团队协作更顺畅
基础类型
原始类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| let name: string = 'BitMosaic';
let age: number = 25;
let isActive: boolean = true;
let empty: null = null; let notDefined: undefined = undefined;
let sym: symbol = Symbol('key');
let bigNum: bigint = 100n;
|
数组
1 2 3 4 5 6
| let numbers: number[] = [1, 2, 3]; let strings: Array<string> = ['a', 'b', 'c'];
let readonlyArr: readonly number[] = [1, 2, 3];
|
元组
1 2 3 4 5 6 7 8
| let tuple: [string, number] = ['hello', 42];
let optionalTuple: [string, number?] = ['hello'];
let restTuple: [string, ...number[]] = ['hello', 1, 2, 3];
|
对象类型
1 2 3 4 5 6 7 8 9 10 11 12 13
| interface User { id: number; name: string; email?: string; readonly createdAt: Date; }
const user: User = { id: 1, name: 'Over', createdAt: new Date(), };
|
函数类型
函数声明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function add(a: number, b: number): number { return a + b; }
const multiply = (a: number, b: number): number => a * b;
function greet(name: string, greeting?: string): string { return `${greeting || 'Hello'}, ${name}!`; }
function greet2(name: string, greeting: string = 'Hello'): string { return `${greeting}, ${name}!`; }
function sum(...numbers: number[]): number { return numbers.reduce((a, b) => a + b, 0); }
|
函数重载
1 2 3 4 5 6 7 8
| function process(x: string): string; function process(x: number): number; function process(x: string | number): string | number { if (typeof x === 'string') { return x.toUpperCase(); } return x * 2; }
|
联合类型与交叉类型
联合类型
1 2 3 4 5 6 7 8 9 10
| type StringOrNumber = string | number;
function printId(id: StringOrNumber) { if (typeof id === 'string') { console.log(id.toUpperCase()); } else { console.log(id); } }
|
交叉类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| interface Name { name: string; }
interface Age { age: number; }
type Person = Name & Age;
const person: Person = { name: 'Over', age: 25, };
|
泛型
泛型是 TypeScript 最强大的特性之一。
泛型函数
1 2 3 4 5 6 7 8
| function identity<T>(arg: T): T { return arg; }
const str = identity<string>('hello'); const num = identity(42);
|
泛型接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| interface Response<T> { code: number; message: string; data: T; }
interface User { id: number; name: string; }
const userResponse: Response<User> = { code: 200, message: 'success', data: { id: 1, name: 'Over' }, };
|
泛型约束
1 2 3 4 5 6 7 8 9 10 11 12 13
| interface Lengthwise { length: number; }
function logLength<T extends Lengthwise>(arg: T): T { console.log(arg.length); return arg; }
logLength('hello'); logLength([1, 2, 3]); logLength(123);
|
常用泛型工具类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| interface User { id: number; name: string; email: string; }
type PartialUser = Partial<User>;
type RequiredUser = Required<PartialUser>;
type UserBasic = Pick<User, 'id' | 'name'>;
type UserWithoutEmail = Omit<User, 'email'>;
type UserMap = Record<string, User>;
type ReadonlyUser = Readonly<User>;
|
类型守卫
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| function padLeft(value: string, padding: string | number) { if (typeof padding === 'number') { return ' '.repeat(padding) + value; } return padding + value; }
interface Bird { fly(): void; }
interface Fish { swim(): void; }
function move(animal: Bird | Fish) { if ('fly' in animal) { animal.fly(); } else { animal.swim(); } }
function isFish(animal: Bird | Fish): animal is Fish { return (animal as Fish).swim !== undefined; }
|
高级类型
条件类型
1 2 3 4 5 6 7 8 9 10
| type IsString<T> = T extends string ? true : false;
type A = IsString<string>; type B = IsString<number>;
type ElementType<T> = T extends (infer E)[] ? E : T;
type C = ElementType<string[]>; type D = ElementType<number>;
|
映射类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| type MyPartial<T> = { [P in keyof T]?: T[P]; };
type MyReadonly<T> = { readonly [P in keyof T]: T[P]; };
type Getters<T> = { [P in keyof T as `get${Capitalize<string & P>}`]: () => T[P]; };
interface Person { name: string; age: number; }
type PersonGetters = Getters<Person>;
|
模板字面量类型
1 2 3 4 5 6 7
| type EventName = 'click' | 'focus' | 'blur'; type EventHandler = `on${Capitalize<EventName>}`;
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'; type ApiEndpoint = `/api/${string}`; type FullEndpoint = `${HttpMethod} ${ApiEndpoint}`;
|
实战技巧
1. 严格模式配置
1 2 3 4 5 6 7 8 9
| { "compilerOptions": { "strict": true, "noImplicitAny": true, "strictNullChecks": true, "strictFunctionTypes": true } }
|
2. 类型断言
1 2 3 4 5 6 7 8
| const input = document.getElementById('input') as HTMLInputElement;
function process(value: string | null) { console.log(value!.toUpperCase()); }
|
3. 声明文件
1 2 3 4 5 6 7 8 9 10 11
| declare module '*.svg' { const content: string; export default content; }
declare global { interface Window { myCustomProperty: string; } }
|
4. 类型与接口的选择
1 2 3 4 5 6 7 8 9 10 11 12
| interface User { name: string; } interface User { age: number; }
type Status = 'pending' | 'success' | 'error'; type Callback = (data: string) => void;
|
常见错误与解决方案
错误1:类型”X”不能赋值给类型”Y”
1 2 3 4 5 6 7 8 9
| const user: { name: string } = { name: 'Over', age: 25 };
interface User { name: string; age?: number; } const user: User = { name: 'Over', age: 25 };
|
错误2:对象可能为 “undefined”
1 2 3 4 5 6 7 8 9
| function getLength(arr?: string[]) { return arr.length; }
function getLength(arr?: string[]) { return arr?.length ?? 0; }
|
推荐学习资源
- TypeScript 官方文档
- TypeScript Deep Dive
- Type Challenges
总结
TypeScript 是提升代码质量和开发效率的利器:
- 从基础类型开始,逐步掌握
- 善用泛型,提高代码复用性
- 理解类型推断,减少冗余类型注解
- 实践类型体操,提升类型编程能力
持续练习,你会发现 TypeScript 让开发变得更加愉快!
有问题欢迎评论区讨论!