𝑻𝒆𝒏𝑪𝒍𝒂𝒘正在头脑风暴···
𝑻𝒆𝒏𝑲𝒊𝑺𝒆𝒀𝒂の𝑨𝒈𝒆𝒏𝒕助手
𝑻𝒆𝒏-𝒇𝒍𝒂𝒔𝒉

TypeScript入门到精通

说实话,刚开始接触TypeScript的时候,我真的是又爱又恨。爱的是它的类型系统能让代码更加健壮,恨的是学习曲线太陡峭了,而且感觉写代码变慢了很多。但用了半年之后,我发现TypeScript真香!今天就和大家分享一下我在使用TypeScript过程中的一些心得和经验。

什么是TypeScript?

TypeScript是JavaScript的超集,由微软开发,它添加了静态类型系统和一些现代JavaScript的特性。简单来说,TypeScript = JavaScript + 类型系统 + ES6+特性。

为什么需要TypeScript?

  1. 类型安全:在编译时就能发现错误,而不是在运行时
  2. 更好的IDE支持:智能提示、代码导航、重构
  3. 代码可读性:通过类型定义让代码更清晰
  4. 重构信心:类型系统让重构更加安全
  5. 团队协作:统一的代码规范和接口定义

基础类型

基本类型

// 字符串
let message: string = 'Hello TypeScript';

// 数字
let count: number = 42;
let price: number = 19.99;
let hex: number = 0xff;
let binary: number = 0b1010;

// 布尔值
let isActive: boolean = true;

// null 和 undefined
let nullable: null = null;
let undefinable: undefined = undefined;

// any 和 unknown
let anyValue: any = '可以是任何类型';
let unknownValue: unknown = '类型未知';

// void
function logMessage(message: string): void {
console.log(message);
}

// never
function throwError(message: string): never {
throw new Error(message);
}

数组类型

// 数组类型
let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ['a', 'b', 'c'];

// 元组类型 - 固定长度的数组
let tuple: [string, number] = ['hello', 123];

// 只读数组
let readonlyArray: readonly number[] = [1, 2, 3];
// readonlyArray.push(4); // 错误,只读数组不能修改

// 可变元组
const [first, second] = tuple;

对象类型

// 基本对象类型
let user: {
name: string;
age: number;
email?: string; // 可选属性
} = {
name: '张三',
age: 25,
email: 'zhangsan@example.com'
};

// 接口
interface User {
name: string;
age: number;
email?: string;
readonly id: string; // 只读属性
sayHello(): void; // 方法
}

let user2: User = {
name: '李四',
age: 30,
id: '123',
sayHello() {
console.log('Hello');
}
};

// 类型别名
type Point = {
x: number;
y: number;
};

let point: Point = { x: 10, y: 20 };

函数类型

// 函数声明
function add(a: number, b: number): number {
return a + b;
}

// 函数表达式
const multiply = (a: number, b: number): number => {
return a * b;
};

// 可选参数
function greet(name: string, greeting?: string): string {
return `${greeting || 'Hello'}, ${name}!`;
}

// 默认参数
function createConfig(options: {
port: number;
host?: string;
debug?: boolean;
} = {
port: 3000,
debug: false
}) {
return options;
}

// 剩余参数
function sum(...numbers: number[]): number {
return numbers.reduce((acc, num) => acc + num, 0);
}

// 函数重载
function process(input: string): string;
function process(input: number): number;
function process(input: string | number): string | number {
if (typeof input === 'string') {
return input.toUpperCase();
}
return input * 2;
}

高级类型

联合类型和交叉类型

// 联合类型
type Result = 'success' | 'error' | 'pending';

function handleResult(status: Result) {
switch (status) {
case 'success':
console.log('操作成功');
break;
case 'error':
console.log('操作失败');
break;
case 'pending':
console.log('处理中...');
break;
}
}

// 交叉类型
type UserWithPermissions = User & {
permissions: string[];
};

let admin: UserWithPermissions = {
name: '管理员',
age: 35,
id: 'admin123',
sayHello() {
console.log('Hello admin');
},
permissions: ['read', 'write', 'delete']
};

类型推断

// 类型推断
let inferredString = 'hello'; // 推断为 string
let inferredNumber = 42; // 推断为 number

// 类型断言
let someValue: any = 'this is a string';
let strLength: number = (someValue as string).length;

// 非空断言
let potentiallyNull: string | null = Math.random() > 0.5 ? 'hello' : null;
let length = potentiallyNull!.length; // ! 表示确定不是 null

泛型

// 基本泛型
function identity<T>(arg: T): T {
return arg;
}

let output1 = identity<string>('hello');
let output2 = identity(42); // 类型推断为 number

// 数组操作
function getFirstElement<T>(arr: T[]): T | undefined {
return arr[0];
}

let numbersArray = [1, 2, 3];
let firstNumber = getFirstElement(numbersArray); // 推断为 number | undefined

// 约束泛型
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(42); // 错误,number 没有 length

// 默认类型参数
function createArray<T = number>(length: number, value: T): T[] {
return Array(length).fill(value);
}

let numberArray = createArray(3, 0); // number[]
let stringArray = createArray(3, ''); // string[]

类型守卫

// typeof 守卫
function isString(value: any): value is string {
return typeof value === 'string';
}

function processValue(value: string | number) {
if (isString(value)) {
console.log(value.toUpperCase()); // 这里 value 被识别为 string
} else {
console.log(value.toFixed(2)); // 这里 value 被识别为 number
}
}

// instanceof 守卫
class Dog {
bark() {
console.log('Woof!');
}
}

class Cat {
meow() {
console.log('Meow!');
}
}

function isAnimal(animal: Dog | Cat): animal is Dog {
return (animal as Dog).bark !== undefined;
}

function makeSound(animal: Dog | Cat) {
if (isAnimal(animal)) {
animal.bark();
} else {
(animal as Cat).meow();
}
}

// in 守卫
interface Bird {
fly(): void;
}

interface Fish {
swim(): void;
}

function move(pet: Bird | Fish) {
if ('fly' in pet) {
pet.fly();
} else {
pet.swim();
}
}

实用工具类型

Partial 和 Required

interface User {
name: string;
age: number;
email?: string;
}

// Partial - 使所有属性可选
type PartialUser = Partial<User>;
let partialUser: PartialUser = {
name: '张三'
// age 和 email 是可选的
};

// Required - 使所有属性必需
type RequiredUser = Required<User>;
let requiredUser: RequiredUser = {
name: '李四',
age: 30,
email: 'lisi@example.com'
};

Pick 和 Omit

interface Product {
id: string;
name: string;
price: number;
description: string;
category: string;
}

// Pick - 选择特定属性
type ProductPreview = Pick<Product, 'id' | 'name' | 'price'>;
let preview: ProductPreview = {
id: '123',
name: '产品名称',
price: 99.99
// description 和 category 没有
};

// Omit - 排除特定属性
type ProductDetails = Omit<Product, 'id' | 'category'>;
let details: ProductDetails = {
name: '产品名称',
price: 99.99,
description: '产品描述'
// id 和 category 没有
};

Record 和 Map

// Record - 创建对象类型
type UserRoles = Record<string, 'admin' | 'user' | 'guest'>;
let roleMapping: UserRoles = {
'zhangsan': 'admin',
'lisi': 'user',
'guest': 'guest'
};

// Map 类型
const userMap = new Map<string, User>();
userMap.set('zhangsan', {
name: '张三',
age: 25
});

条件类型和映射类型

// 条件类型
type ExtractType<T, U> = T extends U ? T : never;
type Numbers = ExtractType<string | number | boolean, number>; // number

// 映射类型
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};

interface MutableUser {
name: string;
age: number;
}

interface ReadonlyUser extends Readonly<MutableUser> {}

let readonlyUser: ReadonlyUser = {
name: '张三',
age: 25
};
// readonlyUser.name = '李四'; // 错误,只读属性

// Partial 映射类型
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

实战应用

React + TypeScript

import React from 'react';

// 组件属性类型
interface ButtonProps {
children: React.ReactNode;
variant?: 'primary' | 'secondary' | 'danger';
size?: 'sm' | 'md' | 'lg';
onClick?: () => void;
disabled?: boolean;
}

const Button: React.FC<ButtonProps> = ({
children,
variant = 'primary',
size = 'md',
onClick,
disabled = false
}) => {
const className = `btn btn-${variant} btn-${size} ${disabled ? 'disabled' : ''}`;

return (
<button className={className} onClick={onClick} disabled={disabled}>
{children}
</button>
);
};

// 使用示例
const App: React.FC = () => {
const handleClick = () => {
console.log('Button clicked');
};

return (
<div>
<Button variant="primary" size="md" onClick={handleClick}>
Click Me
</Button>
<Button variant="danger" size="sm">
Delete
</Button>
</div>
);
};

export default App;

异步操作

// Promise 类型
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}

async function fetchData<T>(url: string): Promise<ApiResponse<T>> {
const response = await fetch(url);

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

return response.json();
}

// 使用示例
interface User {
id: string;
name: string;
email: string;
}

async function loadUser(userId: string) {
try {
const response = await fetchData<User>(`/api/users/${userId}`);
console.log(response.data);
} catch (error) {
console.error('Error loading user:', error);
}
}

数据库操作

// 数据模型
interface User {
id: string;
name: string;
email: string;
age?: number;
createdAt: Date;
updatedAt: Date;
}

// 数据库操作类型
type UserCreate = Omit<User, 'id' | 'createdAt' | 'updatedAt'>;
type UserUpdate = Partial<UserCreate> & { id: string };

class UserService {
async createUser(userData: UserCreate): Promise<User> {
const user = {
...userData,
id: generateId(),
createdAt: new Date(),
updatedAt: new Date()
};

// 保存到数据库
await db.collection('users').insertOne(user);
return user;
}

async updateUser(userId: string, updateData: UserUpdate): Promise<User> {
const result = await db.collection('users').findOneAndUpdate(
{ id: userId },
{
$set: {
...updateData,
updatedAt: new Date()
}
},
{ returnDocument: 'after' }
);

if (!result.value) {
throw new Error('User not found');
}

return result.value;
}
}

配置和工程化

tsconfig.json 配置

{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",

"strictNullChecks": true,
"noImplicitAny": true,
"strictBindCallApply": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,

"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,

"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist"
]
}

ESLint 集成

{
"extends": [
"eslint:recommended",
"@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"rules": {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "warn",
"prefer-const": "error"
}
}

Prettier 配置

{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"arrowParens": "avoid"
}

性能优化技巧

1. 类型定义优化

// 避免过度使用 any
interface User {
name: string;
age: number;
}

// 好的做法
function processUser(user: User): void {
console.log(user.name, user.age);
}

// 不好的做法
function processUserAny(user: any): void {
// 失去了类型检查的好处
}

// 使用类型断言进行优化
function parseJSON<T>(json: string): T {
return JSON.parse(json) as T;
}

const user = parseJSON<User>('{"name": "张三", "age": 25}');

2. 懒加载类型

// 动态导入类型
interface ComponentProps {
// 一些基础属性
}

const LazyComponent = React.lazy(() => import('./Component'));

// 使用
<React.Suspense fallback={<div>Loading...</div>}>
<LazyComponent {...props} />
</React.Suspense>

3. 类型复用

// 创建可复用的类型工具
type PaginationParams = {
page: number;
limit: number;
};

type FilterParams = {
search?: string;
category?: string;
};

type ApiResponse<T> = {
data: T[];
total: number;
page: number;
limit: number;
};

// 复用类型
function fetchPaginatedData<T>(
url: string,
params: PaginationParams & FilterParams
): Promise<ApiResponse<T>> {
return fetch(url + '?' + new URLSearchParams(params as any))
.then(response => response.json());
}

常见问题和解决方案

1. 类型错误处理

// 处理可选属性
interface User {
name: string;
email?: string;
}

function getUserEmail(user: User): string {
// 错误:可能为 undefined
// return user.email;

// 解决方案 1:提供默认值
return user.email || 'default@example.com';

// 解决方案 2:类型守卫
if (user.email) {
return user.email;
}
throw new Error('User has no email');
}

// 处理联合类型
function formatValue(value: string | number): string {
if (typeof value === 'string') {
return value.toUpperCase();
}
return value.toString();
}

2. 泛型约束

// 避免过度泛型
interface ApiResponse<T> {
data: T;
status: number;
}

// 好的做法
function fetchData<T>(url: string): Promise<ApiResponse<T>> {
return fetch(url).then(res => res.json());
}

// 不好的做法
function fetchDataBad(url: string, data: any): Promise<any> {
// 失去了类型检查
return fetch(url, { body: JSON.stringify(data) }).then(res => res.json());
}

3. 类型推断优化

// 利用类型推断
const users: Array<{ id: string; name: string }> = [
{ id: '1', name: '张三' },
{ id: '2', name: '李四' }
];

// 类型推断会自动推断为 Array<{ id: string; name: string }>
// 不需要显式指定类型

总结

TypeScript确实是一个强大的工具,虽然学习曲线有点陡峭,但一旦掌握了,它带来的好处是显而易见的。

在我的开发经历中,TypeScript让我受益匪浅:

  1. 代码质量提升:编译时就能发现很多错误
  2. 开发效率提高:智能提示和类型检查让开发更高效
  3. 重构更安全:有了类型系统,重构更有信心
  4. 代码可读性增强:类型定义让代码更清晰
  5. 团队协作更顺畅:统一的接口和类型定义

最后给大家一个小建议:不要一次性掌握所有TypeScript特性,从最常用的基础类型开始,逐步学习高级特性。在实际项目中多使用,遇到问题多查阅官方文档。

记住,TypeScript不是万能的,它只是一个工具。关键是要学会正确地使用它,让它为我们的开发工作带来便利。希望这篇文章能对你有所帮助,让我们一起在TypeScript的世界里探索更精彩的未来!