Skip to main content

New Blog

学而不思则罔,思而不学则怠

TypeScript: 你的代码小能手!

一、开篇

嘿,你好!今天我们来聊聊TypeScript,这个在程序员圈子里火得就像热锅上的小龙虾一样的东西。为啥这么火?因为它能让JavaScript穿上了西装革履,变得更有条理、更聪明!所以,让我们一起搞懂TypeScript,让你的代码更上一层楼。

二、TypeScript是什么?

简单来说,TypeScript是JavaScript的超集,它添加了类型系统和一些新特性,让JavaScript变得更强大,更易于维护。想象一下,JavaScript就像是那个随性的艺术家,而TypeScript则是穿着整洁西装的建筑师,更稳重、更有条理。

三、为何选择TypeScript?

更好的错误检查:拜TypeScript所赐,你可以在编写代码时就发现潜在错误,而不是等到运行时才知道“哎呀,出错了”。 代码更易于理解:类型注解让你的代码就像是在对后来的自己或其他开发者讲故事,清晰明了。 超棒的工具支持:想要智能提示?自动补全?重构?TypeScript全都满足你!

四、开始你的TypeScript之旅

步骤1:安装

首先,确保你的电脑上装有Node.js。然后打开终端,运行以下命令:

npm install -g typescript

就这么简单,你就迈出了学习TypeScript的第一步。

步骤2:你的第一个TypeScript程序

创建一个名为hello.ts的文件,写入下面的代码:

function sayHello(person: string) {
return 'Hello, ' + person;
}

let user = '大黑';
console.log(sayHello(user));

这里的关键点是类型注解string,它告诉我们person应该是一个字符串。

步骤3:编译并运行

回到你的终端,运行:

tsc hello.ts

这会生成一个hello.js文件。接着,运行这个JS文件:

node hello.js

看!你的第一个TypeScript程序已经成功运行了!

五、深入了解

接下来,我们来深入探讨一下TypeScript的一些基本概念。

类型基础

TypeScript让我们可以显式声明变量的类型,这就是所谓的静态类型。比如:

let isDone: boolean = false;

这里我们声明了一个名为isDone的布尔型变量。

接口

接口是TypeScript的核心概念之一。它们让我们可以定义对象的形状,比如:

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

let viking: Person = { name: 'Viking', age: 30 };

TypeScript也支持面向对象编程中的类。看看下面这个例子:

class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}

泛型

泛型提供了一种方式来确保函数、类或接口可以使用任何类型,而不会丢失其原始类型。看看这个例子:

function identity<T>(arg: T): T {
return arg;
}

这里的<T>就是泛型的标志。

六、TypeScript的“超能力”

定义类型:你是谁?

在TypeScript的世界里,一切都得有个身份证。你得告诉TypeScript,这个变量是个啥,它喜欢啥,不喜欢啥。就像下面这样:

let isStudent: boolean = true; // 告诉TypeScript,我是个布尔值!
let age: number = 20; // 我是数字哦,20岁的小伙子。
let name: string = "大黑"; // 字符串大黑,报道!

这样TypeScript就能知道每个变量的类型,从而确保你不会把苹果放到橘子堆里。

函数参数类型:你要啥?

在TypeScript里,你还得告诉函数,它的参数是啥类型的。这样函数才不会懵圈,不知道该如何处理。

function greet(name: string) {
return `Hello, ${name}!`;
}
greet("小明"); // 正确
greet(42); // 错误:42不是字符串!

可选参数和默认参数:有备无患

TypeScript的函数参数还可以是可选的,或者有默认值。这样你就不必每次都传递所有参数了。

function createGreeting(message: string, userName: string = "大黑") {
return `${message}, ${userName}!`;
}

console.log(createGreeting("你好")); // 输出:"你好, 大黑!"

接口:定义对象的模板

在TypeScript中,你可以使用接口来定义一个对象应该具备哪些属性。这就像是建立了一个标准,所有符合这个接口的对象都得遵守这个标准。

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

let user: User = { name: "小红", age: 18 };

这样,你就能保证所有的User类型对象都有name和age属性。

泛型:类型的变形金刚

泛型让你能够写出更灵活、可复用的代码。就像是给函数或者类装上了一个能自适应不同类型的“变形装置”。

function getArray<T>(items : T[] ) : T[] {
return new Array<T>().concat(items);
}

let numberArray = getArray<number>([5, 10, 15, 20]);
let stringArray = getArray<string>(["小黑", "小白", "小红"]);

枚举:给选项一个名字

枚举是一种特殊的类型,它可以更清晰地表达一组相关值。

enum Color {
Red,
Green,
Blue
}

let c: Color = Color.Green;

这样,你就可以使用Color.Green来代替神秘的数字了。

七、结语

好啦,到此为止我们的TypeScript基础入门之旅就告一段落了。记住,编程是个充满乐趣的旅程,尤其是当你开始掌握像TypeScript这样的强大工具时。所以,拿起你的键盘,开始你的代码之旅吧!

希望这篇博客能让你对TypeScript有了更深入的理解。如果你对TypeScript还有其他疑问,或者想要了解更多编程知识,记得来找我哦!我们下次再见!👋🎉

ts基础知识5 min read

目标:Nest.js常用概念练习

在这个练习中,我们将通过一步步的实践,熟悉Nest.js中的一些常用概念。

第一步,模块

Nest.js使用模块化的结构组织应用。创建一个简单的模块,例如users模块:

nest generate module users

第二步,控制器

在创建的模块中生成一个控制器,用于处理HTTP请求:

nest generate controller users

在控制器中添加一些简单的路由处理逻辑。

第三步,服务

创建一个服务来处理业务逻辑。在模块中生成一个服务:

nest generate service users

在服务中添加一些简单的业务逻辑,例如从数据库中获取用户信息。

第四步,中间件

使用中间件处理HTTP请求。在模块中创建一个中间件:

nest generate middleware logger

在中间件中添加一些简单的请求日志记录逻辑。

第五步,异常过滤器

实现异常过滤器,用于捕获和处理应用中的异常。在模块中生成一个异常过滤器:

nest generate filter exception

在异常过滤器中添加一些简单的异常处理逻辑。

总结

通过这个Nest.js常用概念的练习,我们熟悉了模块、控制器、服务、中间件以及异常过滤器等Nest.js的基本概念。这些概念帮助我们更好地组织和管理应用的结构,并使得开发更加清晰和可维护。

希望这个练习能够帮助你更好地理解和应用Nest.js中的一些关键概念。

练习nest2 min read

目标:React常用Hook及概念练习

在这个练习中,我们将通过一步步的实践,熟悉React中常用的Hook和一些重要的概念。

第一步,useState Hook

使用useState Hook来实现组件状态的管理。

import React, { useState } from 'react';

const Counter = () => {
const [count, setCount] = useState(0);

return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};

export default Counter;

第二步,useEffect Hook

使用useEffect Hook来处理副作用,例如数据获取、订阅等。

import React, { useState, useEffect } from 'react';

const DataFetching = () => {
const [data, setData] = useState([]);

useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/todos')
.then((response) => response.json())
.then((data) => setData(data));
}, []);

return (
<div>
<h2>Data Fetching</h2>
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
</div>
);
};

export default DataFetching;

第三步,useContext Hook

使用useContext Hook来访问React的上下文。

import React, { useContext } from 'react';

const ThemeContext = React.createContext();

const ThemedComponent = () => {
const theme = useContext(ThemeContext);

return (
<div style={{ color: theme === 'dark' ? 'white' : 'black' }}>
Themed Component
</div>
);
};

export const App = () => {
return (
<ThemeContext.Provider value="dark">
<ThemedComponent />
</ThemeContext.Provider>
);
};

第四步,useReducer Hook

使用useReducer Hook来管理复杂的状态逻辑。

import React, { useReducer } from 'react';

const initialState = { count: 0 };

const reducer = (state, action) => {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
};

const CounterWithReducer = () => {
const [state, dispatch] = useReducer(reducer, initialState);

return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
};

export default CounterWithReducer;

第五步,自定义Hook

创建自定义Hook来提取和重用组件逻辑。

import { useState, useEffect } from 'react';

const useDataFetching = (url) => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
setLoading(true);
fetch(url)
.then((response) => response.json())
.then((data) => {
setData(data);
setLoading(false);
});
}, [url]);

return { data, loading };
};

export default useDataFetching;

总结

通过这个React常用Hook及概念的练习,我们熟悉了useStateuseEffectuseContextuseReducer等React Hook,以及自定义Hook的使用。这些Hook能够使我们更轻松地管理组件的状态和副作用,提高代码的可维护性和可重用性。

希望这个练习能够帮助你更深入地理解和应用React中的Hook。

练习react2 min read

目标:实现接口的增删改查

在这个实践中,我们将通过一步步的实践,使用Nest.js和MySQL数据库,实现一个具有增删改查功能的接口。

第一步,配置环境

首先,确保你已经安装了Node.js和npm。接着,通过以下命令安装Nest CLI:

npm install -g @nestjs/cli

然后,创建一个新的Nest.js项目:

nest new my-nest-project

这将为你创建一个基本的Nest.js项目,并安装必要的依赖。

第二步,启动 MySQL

确保你已经安装了MySQL数据库。启动MySQL服务,并创建一个新的数据库用于我们的项目。

第三步,链接 MySQL

使用Nest.js中的TypeORM库来链接MySQL数据库。在src目录下,创建一个typeorm.config.ts文件,配置数据库链接信息。

// src/typeorm.config.ts

import { TypeOrmModuleOptions } from '@nestjs/typeorm';

const config: TypeOrmModuleOptions = {
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'your_username',
password: 'your_password',
database: 'your_database_name',
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
synchronize: true, // Set to false in production
};

export default config;

然后,在主模块 app.module.ts 中引入 TypeOrmModule:

// src/app.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import config from './typeorm.config';

@Module({
imports: [TypeOrmModule.forRoot(config)],
})
export class AppModule {}

第四步,开发接口

创建一个新的模块和控制器用于处理数据的增删改查操作。

nest generate module users
nest generate controller users

users.controller.ts文件中,实现增删改查的业务逻辑。

// src/users/users.controller.ts

import { Controller, Get, Post, Body, Param, Delete, Put } from '@nestjs/common';
import { UsersService } from './users.service';

@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}

@Get()
findAll() {
return this.usersService.findAll();
}

@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(id);
}

@Post()
create(@Body() user) {
return this.usersService.create(user);
}

@Put(':id')
update(@Param('id') id: string, @Body() user) {
return this.usersService.update(id, user);
}

@Delete(':id')
remove(@Param('id') id: string) {
return this.usersService.remove(id);
}
}

第五步,接口联调

通过运行以下命令启动应用程序:

npm run start

通过相关接口访问,你将能够使用这个接口进行增删改查操作。

总结

通过这个Nest.js + MySQL实践,我们实现了一个具有增删改查功能的接口。Nest.js的模块化和TypeORM的数据库支持使得全栈开发更加简单和高效。在实际项目中,你可以根据需要进一步扩展和优化这个基础框架,满足复杂项目的需求。

练习nestmysql2 min read

目标:写个列表+表单

在这个练习中,我们将通过一步步的实践,使用React和Ant Design,实现一个包含增删改查功能的列表和表单。

在这个实践中,我们将创建一个React组件,包含一个用于展示数据的列表,以及一个用于操作数据的表单。通过这个图,我们可以清晰地了解我们要构建的最终目标。

第一步,安装UI库

首先,我们需要安装Ant Design。执行以下命令进行安装:

npm install antd

然后,在项目中引入所需的样式和组件。

第二步,写一个列表

创建一个新的React组件,用于展示列表。在这个组件中,我们将使用Ant Design的Table组件。

import React from 'react';
import { Table, Button } from 'antd';

const MyList = ({ data, onDelete, onEdit }) => {
const columns = [
// Define your columns based on your data structure
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Age', dataIndex: 'age', key: 'age' },
// Add more columns as needed
{
title: 'Actions',
key: 'actions',
render: (text, record) => (
<span>
<Button onClick={() => onEdit(record)}>Edit</Button>
<Button onClick={() => onDelete(record.key)} style={{ marginLeft: 8 }} danger>
Delete
</Button>
</span>
),
},
];

return <Table dataSource={data} columns={columns} />;
};

export default MyList;

第三步,写一个表单

创建一个新的React组件,用于展示表单。在这个组件中,我们将使用Ant Design的FormInput组件。

import React from 'react';
import { Form, Input, Button } from 'antd';

const MyForm = ({ onSubmit, onCancel, form }) => {
const onFinish = (values) => {
onSubmit(values);
form.resetFields();
};

const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};

return (
<Form
form={form}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
layout="vertical"
>
<Form.Item label="Name" name="name" rules={[{ required: true, message: 'Please input the name!' }]}>
<Input />
</Form.Item>
<Form.Item label="Age" name="age" rules={[{ required: true, message: 'Please input the age!' }]}>
<Input />
</Form.Item>

{/* Add more form fields as needed */}

{/* Submit and Cancel buttons */}
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
<Button type="default" onClick={onCancel} style={{ marginLeft: 8 }}>
Cancel
</Button>
</Form.Item>
</Form>
);
};

export default MyForm;

第四步,对接接口

在实际项目中,你需要将列表和表单与后端接口进行对接。使用fetchaxios等工具来发起请求,并在成功后更新列表数据。

总结

通过这个React + Ant Design练习,我们实现了一个具有增删改查功能的列表和表单。React的组件化和Ant Design的组件库让前端开发更加高效。在实际项目中,你可以根据需要进一步扩展和优化这个基础组件,满足复杂的前端需求。

练习react3 min read

目标:写个接口

在这篇文章中,我们将通过一步步的实践,从配置环境到最终开发一个简单的接口,展示Nest.js在全栈开发中的强大功能。

第一步,配置环境

首先,确保你已经安装了Node.js和npm。接着,通过以下命令安装Nest CLI:

npm install -g @nestjs/cli

创建一个新的Nest.js项目:

nest new my-nest-project

这将为你创建一个基本的Nest.js项目,并安装必要的依赖。

第二步,了解目录

Nest.js采用了模块化的目录结构,主要包括srcdist和一些配置文件。了解这些目录结构将有助于你更好地组织和管理项目。

  • src: 包含项目的源代码。
  • dist: 包含项目的编译输出。
  • main.ts: 应用程序的入口文件。
  • app.module.ts: 应用程序的主模块。

第三步,创建模块

Nest.js的模块是应用程序的基本构建块。使用以下命令创建一个新模块:

nest generate module users

这将在src目录下创建一个users模块,并自动在app.module.ts中导入它。

第四步,开发接口

users模块中,使用以下命令创建一个控制器:

nest generate controller users

这将为你创建一个基本的用户控制器。在该控制器中,你可以定义路由和处理请求的方法,实现接口的具体逻辑。

第五步,接口联调

通过运行以下命令启动应用程序:

npm run start

访问http://localhost:3000/users,你将能够看到你刚刚创建的用户接口的默认响应。

总结

通过这个简单的Nest.js实践,我们完成了从环境配置到接口开发的全过程。Nest.js的模块化和依赖注入机制使得全栈开发更加简单和高效。在实际项目中,你可以根据需要进一步扩展和优化这个基础框架,满足复杂项目的需求。

希望这篇文章能够帮助你入门Nest.js,并在实践中更加熟练地应用它的强大功能。

练习nest2 min read

目标:写个页面

在这个指南中,我们将一步步地进行React全栈开发,目标是创建一个简单的页面。我们将探讨环境配置、页面编写、页面间的导航和参数传递、组件间的通信以及接口请求等关键步骤。

第一步,配置环境

在进行React全栈开发之前,首先需要配置开发环境。我们将使用React及其生态中的一些关键库,例如react-domnest。以下是配置环境的基本步骤:

代码示例:package.json

{
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"nest": "^x.x.x"
// 其他依赖
},
"scripts": {
"start": "your-start-script",
// 其他脚本
}
}

代码示例:babel.config.js

module.exports = {
presets: ['@babel/preset-env', '@babel/preset-react'],
};

第二步,写个页面

一旦环境配置完成,我们可以开始编写我们的第一个页面。这将涉及到创建React组件以及使用一些基本的UI元素。

代码示例:src/pages/Home.js

import React from 'react';

const Home = () => {
return (
<div>
<h1>Welcome to our React Full-Stack Blog</h1>
<p>This is the home page of our application.</p>
</div>
);
};

export default Home;

第三步,页面跳转传参

为了使我们的应用更加交互,我们将探讨页面之间的导航和参数传递。

1. 两种路由导航写法

在React中,有多种方式可以实现路由导航。我们将研究两种常用的方法。

代码示例:使用React Router进行导航
npm install react-router-dom
import { BrowserRouter as Router, Link, Route } from 'react-router-dom';

const App = () => {
return (
<Router>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</Router>
);
};
代码示例:使用history进行导航
import { createBrowserHistory } from 'history';

const history = createBrowserHistory();

const navigateTo = (url) => {
history.push(url);
};

// 使用
navigateTo('/about');

2. 三种路由参数获取方法

在React中,获取路由参数有多种方式,我们将讨论其中的三种方法。

代码示例:使用useParams Hook
import { useParams } from 'react-router-dom';

const BlogPost = () => {
const { postId } = useParams();

return <p>Displaying blog post #{postId}</p>;
};
代码示例:使用withRouter HOC
import { withRouter } from 'react-router-dom';

const BlogPost = (props) => {
const { match } = props;
const postId = match.params.postId;

return <p>Displaying blog post #{postId}</p>;
};

export default withRouter(BlogPost);
代码示例:使用useLocation Hook
import { useLocation } from 'react-router-dom';

const BlogPost = () => {
const location = useLocation();
const postId = location.pathname.split('/').pop();

return <p>Displaying blog post #{postId}</p>;
};

第四步,组件间通信

在React开发中,组件间通信是一个关键的主题。我们将讨论父子组件通信、兄弟组件通信以及爷孙组件通信(跨组件通信)。

1. 父子组件通信

在React中,通过props可以实现父子组件之间的通信。

代码示例:父组件传递数据给子组件
// ParentComponent.js
import React from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
const data = 'Data from parent';

return <ChildComponent data={data} />;
};

// ChildComponent.js
import React from 'react';

const ChildComponent = (props) => {
const { data } = props;

return <p>Data received from parent: {data}</p>;
};

export default ChildComponent;

2. 兄弟组件通信

为了实现兄弟组件之间的通信,可以通过共享状态或者使用父组件作为中介。

代码示例:使用父组件作为中介
// ParentComponent.js
import React, { useState } from 'react';
import BrotherComponentA from './BrotherComponentA';
import BrotherComponentB from './BrotherComponentB';

const ParentComponent = () => {
const [sharedData, setSharedData] = useState('');

return (
<>
<BrotherComponentA setSharedData={setSharedData} />
<BrotherComponentB sharedData={sharedData} />
</>
);
};

// BrotherComponentA.js
import React from 'react';

const BrotherComponentA = (props) => {
const { setSharedData } = props;

const handleChange = (e) => {
setSharedData(e.target.value);
};

return <input type="text" onChange={handleChange} />;
};

// BrotherComponentB.js
import React from 'react';

const BrotherComponentB = (props) => {
const { sharedData } = props;

return <p>Data shared between brothers: {sharedData}</p>;
};

export { BrotherComponentA, BrotherComponentB };

3. 爷孙组件通信(跨组件通信)

对于爷孙组件之间的通信,可以使用Context API或者第三方状态管理工具,如Redux。

第五步,接口请求

在现代的Web应用中,与后端进行数据交互是不可避免的。我们将讨论如何在React

中进行接口请求。

代码示例:使用fetch进行简单的接口请求

import React, { useState, useEffect } from 'react';

const ApiExample = () => {
const [data, setData] = useState([]);

useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => response.json())
.then((data) => setData(data))
.catch((error) => console.error('Error fetching data:', error));
}, []);

return (
<div>
<h2>API Example</h2>
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
</div>
);
};

export default ApiExample;

总结

在这篇React全栈开发实践指南中,我们覆盖了从环境配置到页面编写、导航、组件通信以及接口请求的各个方面。通过这些实例,希望读者能够建立起对React全栈开发的整体认识,并能够在实际项目中灵活运用这些技术。

以上示例代码仅为演示目的,实际项目中可能需要根据具体情况进行调整和优化。希望这篇指南对你在React全栈开发中的学习和实践有所帮助。

练习react5 min read