大白话TypeScript第四章项目实践

news/2025/2/25 10:42:35

第四章是项目实践,这就好比你学了很多做菜的技巧,现在要亲自下厨做几道菜来检验和提升自己的厨艺。下面给你介绍小型命令行项目和 Web 应用项目这两类实践,帮你巩固 TypeScript 知识。

小型命令行项目 - 简易文件搜索工具
项目描述

这个简易文件搜索工具就像是一个小侦探,能在你指定的文件夹里帮你找出包含特定关键字的文件。你在命令行里告诉它要搜索哪个文件夹,以及要找的关键字,它就会把符合条件的文件列出来。

巩固要点

这个项目能让你熟悉如何处理命令行输入、进行文件系统操作,还能加深对 TypeScript 里异步操作的理解。

代码示例
typescript">import fs from 'fs';
import path from 'path';
import readline from 'readline';

// 创建一个 readline 接口,用于和用户在命令行交互
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

// 定义一个异步函数来搜索文件
async function searchFiles(folderPath: string, keyword: string) {
    try {
        // 读取指定文件夹下的所有文件和子文件夹
        const files = await fs.promises.readdir(folderPath);
        for (const file of files) {
            const filePath = path.join(folderPath, file);
            // 检查当前路径是文件还是文件夹
            const stat = await fs.promises.stat(filePath);
            if (stat.isDirectory()) {
                // 如果是文件夹,递归调用 searchFiles 函数继续搜索
                await searchFiles(filePath, keyword);
            } else {
                // 如果是文件,读取文件内容
                const data = await fs.promises.readFile(filePath, 'utf8');
                if (data.includes(keyword)) {
                    // 如果文件内容包含关键字,打印文件路径
                    console.log(filePath);
                }
            }
        }
    } catch (error) {
        // 处理可能出现的错误
        console.error('搜索过程中出现错误:', error);
    }
}

// 询问用户要搜索的文件夹路径
rl.question('请输入要搜索的文件夹路径: ', (folderPath) => {
    // 询问用户要搜索的关键字
    rl.question('请输入要搜索的关键字: ', (keyword) => {
        // 调用搜索函数开始搜索
        searchFiles(folderPath, keyword).then(() => {
            // 搜索完成后关闭 readline 接口
            rl.close();
        });
    });
});

代码解释
  1. 导入模块:导入了 fs(用于文件系统操作)、path(用于处理文件路径)和 readline(用于和用户在命令行交互)这几个模块。
  2. 创建 readline 接口:通过 readline.createInterface 创建了一个接口,方便我们从命令行获取用户输入。
  3. 定义搜索函数searchFiles 是一个异步函数,它会读取指定文件夹下的所有文件和子文件夹。如果遇到文件夹,就递归调用自己继续搜索;如果遇到文件,就读取文件内容,检查是否包含关键字。
  4. 获取用户输入:通过 rl.question 询问用户要搜索的文件夹路径和关键字,然后调用 searchFiles 函数开始搜索。
  5. 错误处理:使用 try...catch 块来捕获和处理搜索过程中可能出现的错误。
Web 应用项目 - 简单的博客列表展示
项目描述

这是一个简单的 Web 应用,它会在网页上展示一个博客文章列表。每篇文章有标题、作者和简要内容,你可以通过修改代码里的文章数据来更新列表。

巩固要点

这个项目能让你学会如何结合 HTML、CSS 和 TypeScript 来开发 Web 应用,掌握 DOM 操作(也就是操作网页上的元素)和事件处理。

代码示例

HTML 文件(index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>简单博客列表</title>
    <style>
        /* 简单的样式,让博客列表看起来更美观 */
        body {
            font-family: Arial, sans-serif;
            padding: 20px;
        }

        .blog-post {
            border: 1px solid #ccc;
            padding: 10px;
            margin-bottom: 10px;
        }
    </style>
</head>

<body>
    <h1>博客列表</h1>
    <div id="blog-list"></div>
    <!-- 引入编译后的 JavaScript 文件 -->
    <script src="main.js"></script>
</body>

</html>

TypeScript 文件(main.ts

typescript">// 定义博客文章的类型
type BlogPost = {
    title: string;
    author: string;
    content: string;
};

// 定义一些博客文章数据
const blogPosts: BlogPost[] = [
    {
        title: "第一篇博客",
        author: "张三",
        content: "这是我的第一篇博客,分享一些生活趣事。"
    },
    {
        title: "技术分享",
        author: "李四",
        content: "今天来分享一些前端开发的小技巧。"
    }
];

// 获取用于展示博客列表的 DOM 元素
const blogList = document.getElementById('blog-list');

if (blogList) {
    // 遍历博客文章数组
    blogPosts.forEach(post => {
        // 创建一个 div 元素来包裹每篇博客文章
        const postDiv = document.createElement('div');
        postDiv.classList.add('blog-post');

        // 创建标题元素
        const titleElement = document.createElement('h2');
        titleElement.textContent = post.title;

        // 创建作者元素
        const authorElement = document.createElement('p');
        authorElement.textContent = `作者: ${post.author}`;

        // 创建内容元素
        const contentElement = document.createElement('p');
        contentElement.textContent = post.content;

        // 将标题、作者和内容元素添加到 div 元素中
        postDiv.appendChild(titleElement);
        postDiv.appendChild(authorElement);
        postDiv.appendChild(contentElement);

        // 将包含博客文章信息的 div 元素添加到博客列表中
        blogList.appendChild(postDiv);
    });
}

代码解释
  1. HTML 文件:创建了一个简单的网页结构,有一个标题和一个用于展示博客列表的 div 元素,同时引入了编译后的 JavaScript 文件。
  2. TypeScript 文件
    • 定义类型:使用 type 定义了 BlogPost 类型,规定了博客文章应该包含的属性。
    • 准备数据:创建了一个 blogPosts 数组,里面存放了一些博客文章的数据。
    • 获取 DOM 元素:通过 document.getElementById 获取用于展示博客列表的 div 元素。
    • 遍历数据并创建元素:使用 forEach 遍历 blogPosts 数组,为每篇文章创建相应的 divh2p 元素,并将它们添加到网页中。

通过这两个项目实践,你可以更好地掌握 TypeScript 在不同场景下的应用,提升自己的编程能力。

那么,除了文件搜索工具,还可以用 TypeScript 实现哪些小型命令行项目?

除了文件搜索工具外,还有许多适合用 TypeScript 实现的小型命令行项目,以下为你详细介绍:

1. 任务管理工具

  • 功能描述:这是一个能帮助你管理日常任务的工具。你可以添加新任务,为每个任务设置截止日期和优先级;查看当前所有未完成的任务列表,列表会按照优先级或截止日期排序;标记任务为已完成,完成的任务会被归档,你也能随时查看历史完成的任务;还可以删除不再需要的任务。
  • 巩固要点:需要使用数组和对象来存储任务数据,学会使用条件判断和循环来处理任务的筛选和排序,掌握文件系统操作来实现任务数据的持久化存储。
  • 代码示例
typescript">import fs from 'fs';
import readline from 'readline';

// 定义任务类型
type Task = {
    id: number;
    description: string;
    completed: boolean;
};

// 读取任务数据
function readTasks(): Task[] {
    try {
        const data = fs.readFileSync('tasks.json', 'utf8');
        return JSON.parse(data);
    } catch (error) {
        return [];
    }
}

// 保存任务数据
function saveTasks(tasks: Task[]) {
    fs.writeFileSync('tasks.json', JSON.stringify(tasks, null, 2));
}

// 创建新任务
function createTask(description: string) {
    const tasks = readTasks();
    const newTask: Task = {
        id: tasks.length > 0 ? tasks[tasks.length - 1].id + 1 : 1,
        description,
        completed: false
    };
    tasks.push(newTask);
    saveTasks(tasks);
    console.log('任务已添加');
}

// 列出所有任务
function listTasks() {
    const tasks = readTasks();
    tasks.forEach(task => {
        console.log(`${task.id}. [${task.completed ? 'X' : ' '}] ${task.description}`);
    });
}

// 标记任务为已完成
function completeTask(id: number) {
    const tasks = readTasks();
    const task = tasks.find(t => t.id === id);
    if (task) {
        task.completed = true;
        saveTasks(tasks);
        console.log('任务已标记为完成');
    } else {
        console.log('未找到该任务');
    }
}

// 命令行交互
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

rl.question('请输入命令 (add <描述> | list | complete <id>): ', (command) => {
    const [action, ...args] = command.split(' ');
    switch (action) {
        case 'add':
            createTask(args.join(' '));
            break;
        case 'list':
            listTasks();
            break;
        case 'complete':
            const id = parseInt(args[0]);
            if (!isNaN(id)) {
                completeTask(id);
            } else {
                console.log('无效的任务 ID');
            }
            break;
        default:
            console.log('无效的命令');
    }
    rl.close();
});

2. 单词拼写检查器

  • 功能描述:该工具可以检查用户输入的单词是否拼写正确。它会有一个内置的词典,当用户输入一个单词后,工具会在词典中查找该单词,如果找不到,就会提示拼写错误,并可以提供一些可能正确的拼写建议。
  • 巩固要点:要学会使用字符串处理方法来比较单词,掌握数据结构如数组或集合来存储词典,使用算法来生成可能的拼写建议。
  • 代码示例
typescript">import readline from 'readline';

// 简单的词典
const dictionary = ['apple', 'banana', 'cherry', 'date'];

function checkSpelling(word: string) {
    if (dictionary.includes(word)) {
        console.log(`${word} 拼写正确`);
    } else {
        console.log(`${word} 拼写错误`);
        // 简单示例:查找可能的建议
        const suggestions = dictionary.filter(dictWord => {
            const distance = levenshteinDistance(word, dictWord);
            return distance <= 1;
        });
        if (suggestions.length > 0) {
            console.log(`可能的正确拼写: ${suggestions.join(', ')}`);
        }
    }
}

// 计算莱文斯坦距离
function levenshteinDistance(a: string, b: string): number {
    const m = a.length;
    const n = b.length;
    const dp: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));

    for (let i = 0; i <= m; i++) {
        for (let j = 0; j <= n; j++) {
            if (i === 0) {
                dp[i][j] = j;
            } else if (j === 0) {
                dp[i][j] = i;
            } else if (a[i - 1] === b[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
            }
        }
    }

    return dp[m][n];
}

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

rl.question('请输入一个单词进行拼写检查: ', (word) => {
    checkSpelling(word.trim().toLowerCase());
    rl.close();
});

3. 汇率转换器

  • 功能描述:这个工具能让你方便地进行不同货币之间的汇率转换。你可以设置不同货币的汇率,输入要转换的金额和目标货币,工具会计算并输出转换后的金额。
  • 巩固要点:运用数学运算进行金额的转换,使用对象来存储不同货币的汇率信息,处理用户输入的金额和货币类型。
  • 代码示例
typescript">import readline from 'readline';

// 汇率数据
const exchangeRates = {
    USD: 1,
    EUR: 0.9,
    GBP: 0.8,
    JPY: 110
};

function convertCurrency(amount: number, fromCurrency: string, toCurrency: string) {
    if (!exchangeRates[fromCurrency] || !exchangeRates[toCurrency]) {
        console.log('不支持的货币类型');
        return;
    }
    const convertedAmount = amount * (exchangeRates[toCurrency] / exchangeRates[fromCurrency]);
    console.log(`${amount} ${fromCurrency} = ${convertedAmount.toFixed(2)} ${toCurrency}`);
}

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

rl.question('请输入要转换的金额: ', (amountStr) => {
    const amount = parseFloat(amountStr);
    if (isNaN(amount)) {
        console.log('无效的金额');
        rl.close();
        return;
    }
    rl.question('请输入源货币 (如 USD): ', (fromCurrency) => {
        rl.question('请输入目标货币 (如 EUR): ', (toCurrency) => {
            convertCurrency(amount, fromCurrency.toUpperCase(), toCurrency.toUpperCase());
            rl.close();
        });
    });
});

4. 随机密码生成器

  • 功能描述:根据用户指定的密码长度和包含的字符类型(如字母、数字、特殊字符)生成随机密码。用户可以通过命令行参数来控制密码的复杂度和长度。
  • 巩固要点:掌握随机数生成和字符串拼接的方法,根据用户输入的条件生成符合要求的密码。
  • 代码示例
typescript">import readline from 'readline';

const lowercase = 'abcdefghijklmnopqrstuvwxyz';
const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const numbers = '0123456789';
const symbols = '!@#$%^&*()_+-=[]{}|;:\",./<>?';

function generatePassword(length: number, includeUppercase: boolean, includeNumbers: boolean, includeSymbols: boolean) {
    let characters = lowercase;
    if (includeUppercase) characters += uppercase;
    if (includeNumbers) characters += numbers;
    if (includeSymbols) characters += symbols;

    let password = '';
    for (let i = 0; i < length; i++) {
        const randomIndex = Math.floor(Math.random() * characters.length);
        password += characters.charAt(randomIndex);
    }
    return password;
}

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

rl.question('请输入密码长度: ', (lengthStr) => {
    const length = parseInt(lengthStr);
    if (isNaN(length) || length <= 0) {
        console.log('无效的密码长度');
        rl.close();
        return;
    }
    rl.question('是否包含大写字母 (y/n): ', (includeUppercaseStr) => {
        rl.question('是否包含数字 (y/n): ', (includeNumbersStr) => {
            rl.question('是否包含特殊字符 (y/n): ', (includeSymbolsStr) => {
                const includeUppercase = includeUppercaseStr.toLowerCase() === 'y';
                const includeNumbers = includeNumbersStr.toLowerCase() === 'y';
                const includeSymbols = includeSymbolsStr.toLowerCase() === 'y';
                const password = generatePassword(length, includeUppercase, includeNumbers, includeSymbols);
                console.log('生成的密码: ', password);
                rl.close();
            });
        });
    });
});

http://www.niftyadmin.cn/n/5865397.html

相关文章

EasyExcel 实践案例:打印工资条

文章目录 &#x1f3af; 1. 每个人一个 Excel 文件&#xff08;单个对象填充&#xff09;&#x1f3af; 2. 每个人一个 Sheet&#xff08;批量生成工资单&#xff09;&#x1f3af; 3. 一张工资表&#xff0c;多个员工&#xff08;列表数据填充&#xff09;&#x1f4cc; 总结✅…

Winform工具箱、属性、事件

工具箱 Button------按钮&#xff1a;用户可以点击的按钮控件。 CheckBox------复选框&#xff1a;允许用户选择或取消选择选项的复选框。 CheckedListBox&#xff1a;结合了ListBox和CheckBox的功能&#xff0c;允许多项选择。 ColorDialog------颜色选择对话框&#xff1a;用…

九、k8s:ingress

k8s对外服务之ingress&#xff1a; service的作用&#xff1a; NodePort&#xff1a;会在每个节点开放一个端口&#xff0c;端口号30000-32767。 也是只能用于内网访问&#xff0c;四层转发。实现负载均衡。不能基于域名进行访问。 clusterip:service的默认类型&#xff0c…

Apache Doris:一款高性能的实时数据仓库

Apache Doris 是一款基于 MPP 架构的高性能、实时分析型数据库。它以高效、简单和统一的特性著称&#xff0c;能够在亚秒级的时间内返回海量数据的查询结果。Doris 既能支持高并发的点查询场景&#xff0c;也能支持高吞吐的复杂分析场景。 Apache Doris 最初是百度广告报表业务…

数字IC后端设计实现OCC(On-chip Clock Controller)电路介绍及时钟树综合案例

数字IC后端时钟树综合专题&#xff08;OCC电路案例分享&#xff09; 复杂时钟设计时钟树综合(clock tree synthesis)常见20个典型案例 1、什么是OCC&#xff1f; 片上时钟控制器(On-chip Clock Controllers &#xff0c;OCC)&#xff0c;也称为扫描时钟控制器(Scan Clock Con…

我与Linux的爱恋:了解信号量+共享内存+消息队列的应用

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;Linux的学习 文章目录 信号量共享内存应用---Server&Client通信client.ccserver.ccnamepipe.hppShm.hpp 消息队列——实现Client&ServerCom.hppClient.ccServer.cc 信号量 信号量…

用Deepseek直接在word中完成论文的润色(中-中,中-英, 英-中)

最近&#xff0c;各行各业仿佛掀起了一场“Deepseek接入大赛”——从大公司到小微企业&#xff0c;从手机助手到扫地机器人&#xff0c;似乎不接入Deepseek都不好意思说自己是“智能体”了。就连我家楼下的自动售货机都开始“思考”该给我推荐什么零食了&#xff08;虽然它最后…

MybatisPlus-扩展功能-枚举处理器

在Mybatis里有一个叫TypeHandler的类型处理器&#xff0c;我们常见的PO当中的这些成员变量的数据类型&#xff0c;它都有对应的处理器&#xff0c;因此它就能自动实现这些Java数据类型与数据库类型的相互转换。 它里面还有一个叫EnumOrdinalTypeHandler的枚举处理器&#xff0…