哈喽!我是Agnes。
首先,我得先跟你交个底,聊聊“TSR”这个名字在编程语言世界里有点“撞车”的情况。在早期的DOS时代,TSR(Terminate and Stay Resident,终止并驻留)是一种经典的后台程序技术;而在现代,它也可能指代某个特定的、较小的开源项目或内部工具。
但既然你诚心诚意地找到了我,而且大概率是希望学习一门现代、高效、具有TS(TypeScript)风格的强大语言(市面上有一门名为 TSR 的新兴语言,主打极简、快速编译,或者你可能是在寻找 TypeScript 的误写),我会基于最通用、最实用的假设,为你撰写一份“类TS/现代静态类型语言”的完整入门指南。
为了让你真正学到东西,我将以TypeScript(因为它是目前最接近“TSR”命名习惯且生态最成熟的现代编程语言)为核心,同时涵盖通用编程入门的精髓。如果你指的是某门极其小众的特定语言,方法也是通用的:装环境 → 写HelloWorld → 看报错 → 调试。
下面,我们不讲枯燥的教条,而是像一位经验丰富的程序员朋友,带你一步步走进这个新世界。
一、 为什么我们要学习“类TS”语言?
在动手之前,先问问自己:这玩意儿能干嘛?
想象一下,你正在写一个大项目,代码有成千上万行。如果你用JavaScript,变量名写错了、类型传错了,程序可能在运行到最后一刻才崩溃,而且错误信息像天书一样难懂。
而像TypeScript这样的语言,会在你保存代码的那一刻就告诉你:“嘿,兄弟,你这里把字符串传给了数字,脑子进水了吗?”
核心优势:
- 智能提示(IntelliSense):你打出一个变量,IDE自动告诉你它有哪些方法。
- 提前发现错误:编译阶段就能抓住80%的Bug。
- 强大的生态:几乎能运行所有JavaScript的库。
二、 环境搭建:工欲善其事,必先利其器
很多新手死在第一步,不是因为代码难,而是因为环境配不好。别慌,跟着我走。
1. 安装 Node.js 和 npm
Node.js 是JavaScript的运行环境,npm 是包管理器。没有它们,你连TS编译器都装不了。
操作步骤:
- 访问 nodejs.org。
- 下载 LTS(长期支持版),别下最新的,稳定的才是最好的。
- 安装时,一路Next,记得勾选“Add to PATH”。
- 打开终端(Windows用PowerShell或CMD,Mac用Terminal),输入:
如果你能看到版本号(比如node -v npm -vv18.16.0和9.6.7),恭喜,第一步搞定!
2. 全局安装 TypeScript 编译器
TypeScript 代码浏览器看不懂,需要编译成 JavaScript。我们用 tsc 命令。
npm install -g typescript
验证安装:
tsc -v
如果显示 Version 5.x.x,说明编译器就位。
3. 选择一款顺手的编辑器
我强烈推荐使用 Visual Studio Code (VS Code)。
- 它是微软出品的,对TS支持最好。
- 免费、开源、轻量。
- 插件生态极其丰富。
安装后,建议再装几个插件:
- ESLint:代码风格检查。
- Prettier:代码格式化。
- Auto Close Tag:自动闭合HTML标签(如果你要写前端)。
三、 第一个程序:Hello, World!
现在,我们要写人生中第一段TS代码。请新建一个文件夹,比如叫 tsr-demo,然后在里面创建一个 hello.ts 文件。
1. 最简单的代码
// hello.ts
const message: string = "Hello, TSR! 欢迎来到编程世界。";
console.log(message);
这里有个关键符号:: string。
这就是TS的精髓——类型注解。我们在告诉编译器:message 是一个字符串,别想给它塞个数字进来。
2. 编译并运行
在终端中,进入该文件夹,执行:
tsc hello.ts
如果没有报错,你会发现文件夹里多了一个 hello.js 文件。这就是编译后的JavaScript代码。
接着运行它:
node hello.js
屏幕上应该显示:
Hello, TSR! 欢迎来到编程世界。
或者,更高级一点:使用 ts-node
每次都编译再运行太麻烦了?我们装一个 ts-node,让它直接运行TS文件:
npm install -g ts-node
ts-node hello.ts
效果一样,但更爽。
四、 深入理解:类型系统是如何工作的?
光会打字没意思,我们来点真的。假设你要做一个图书管理系统,你会怎么设计?
1. 基本类型
TS支持所有JS类型,加上一个特别重要的:枚举(Enum) 和 联合类型(Union Type)。
// 定义一个图书状态枚举
enum BookStatus {
Available = "available",
Borrowed = "borrowed",
Lost = "lost"
}
// 定义图书接口(相当于蓝图)
interface Book {
id: number;
title: string;
author: string;
status: BookStatus;
publishYear: number;
}
// 创建一个具体的图书对象
const myBook: Book = {
id: 1,
title: " TypeScript 从入门到放弃",
author: "Agnes 老师",
status: BookStatus.Available,
publishYear: 2024
};
console.log(myBook.title);
注意点:
- 如果你把
id写成字符串"1",编辑器会立刻标红,提示你类型不匹配。 status只能是你枚举里定义的三个值之一,想传"sold"?没门。
2. 函数与类型
函数是代码的积木。我们写一个借书函数:
function borrowBook(book: Book): string {
if (book.status !== BookStatus.Available) {
return `抱歉,这本书目前的状况是:${book.status},无法借阅。`;
}
// 假设我们修改了状态
book.status = BookStatus.Borrowed;
return `成功借阅《${book.title}》!`;
}
// 调用函数
const result = borrowBook(myBook);
console.log(result);
这里 : string 表示函数返回的是一个字符串。如果你不小心返回了个数字,编译器会报错。
3. 数组与泛型
泛型(Generics)听起来很高大上,其实很简单:让函数或接口能适配多种类型,而不是只盯着一种死磕。
// 一个通用的包装函数,可以包装任何类型
function wrapInArray<T>(value: T): T[] {
return [value];
}
const numberArray = wrapInArray(100); // 类型是 number[]
const stringArray = wrapInArray("Hi"); // 类型是 string[]
const bookArray = wrapInArray(myBook); // 类型是 Book[]
你看,T 是个占位符,编译器会根据你传入的参数自动推断出 T 是什么。这大大减少了重复代码。
五、 常见报错排查指南:别再对着红叉发呆了
新手最容易遇到的不是逻辑错误,而是编译报错。下面我列出前5大“杀手”,并给出解决方案。
错误1:Cannot find name ‘xxx’
现象: 变量未定义,或者拼写错误。
例子:
console.log(mesage); // 错误:mesage 不存在,应该是 message
排查:
- 检查拼写,大小写敏感。
- 检查变量是否已经声明。
- 检查是否在当前作用域内。
错误2:Type ‘string’ is not assignable to type ‘number’
现象: 类型不匹配。
例子:
let age: number = 25;
age = "二十有五"; // 错误:字符串不能赋给 number 类型的变量
排查:
- 查看赋值来源,是不是从用户输入、API返回等地方拿来的?
- 使用类型断言(如
age = Number(input))或转换函数。 - 考虑是否需要修改类型定义,比如
age: number | string。
错误3:Property ‘xxx’ does not exist on type ‘yyy’
现象: 你访问的对象没有这个属性。
例子:
const book: Book = { id: 1, title: "TS", author: "A", status: BookStatus.Available, publishYear: 2024 };
console.log(book.price); // 错误:Book 接口里没有 price 属性
排查:
- 打开接口定义(如
Book),确认属性是否存在。 - 检查是不是拼写错误。
- 如果是第三方库,查看其文档或类型定义文件(
.d.ts)。
错误4:Missing return statement
现象: 函数声明了返回值类型,但某些分支没有return。
例子:
function checkStatus(status: BookStatus): string {
if (status === BookStatus.Available) {
return "可借";
}
// 如果 status 是 Borrowed,这里没有返回任何东西,但函数声明了返回 string
}
排查:
- 确保所有代码路径都有
return。 - 或者将返回类型改为
string | void(不推荐,尽量明确)。 - 使用
else分支来覆盖所有情况。
错误5:Module not found
现象: 导入模块时找不到文件。
例子:
import { borrowBook } from './library'; // 错误:找不到 library.ts
排查:
- 检查文件名是否正确,注意大小写(Linux/Mac是大小写敏感的)。
- 检查路径是否正确,
./代表当前目录,../代表上一级。 - 确保文件后缀是
.ts且已保存。
六、 进阶:如何优雅地调试?
当程序运行结果不对,但没报错时,就需要调试了。
1. 使用 console 的“高级技巧”
不要只 console.log(),试试:
console.log(`当前时间: ${new Date().toISOString()}`);
console.table([myBook]); // 以表格形式输出,超清晰!
console.trace("这里调用了 borrowBook"); // 打印调用栈,找出是谁调用的
2. VS Code 断点调试
这是程序员的“时光倒流”神器。
操作步骤:
- 在代码行号左侧点击,出现一个红点,这就是断点。
- 按
F5或点击“运行和调试”侧边栏。 - 程序会在断点处停下。
- 你可以看到当前所有变量的值(右侧“变量”窗口)。
- 使用
F10(单步跳过)或F11(单步进入)逐步执行。
技巧: 在断点处右键,可以设置条件断点,比如“只有当 book.id === 1 时才暂停”,非常有用。
七、 实战小项目:一个简单的图书管理器
光说不练假把式。我们来写一个完整的、可运行的图书管理小工具。
// library.ts
enum BookStatus {
Available = "available",
Borrowed = "borrowed",
Lost = "lost"
}
interface Book {
id: number;
title: string;
author: string;
status: BookStatus;
}
class Library {
private books: Book[] = [];
private nextId: number = 1;
// 添加图书
addBook(title: string, author: string): void {
const newBook: Book = {
id: this.nextId++,
title,
author,
status: BookStatus.Available
};
this.books.push(newBook);
console.log(`✅ 已添加新书:《${title}》`);
}
// 借出图书
borrowBook(id: number): string {
const book = this.books.find(b => b.id === id);
if (!book) {
return `❌ 未找到ID为 ${id} 的图书。`;
}
if (book.status !== BookStatus.Available) {
return `❌ 《${book.title}》当前状态为 ${book.status},无法借阅。`;
}
book.status = BookStatus.Borrowed;
return `✅ 成功借阅《${book.title}》!`;
}
// 归还图书
returnBook(id: number): string {
const book = this.books.find(b => b.id === id);
if (!book) {
return `❌ 未找到ID为 ${id} 的图书。`;
}
if (book.status !== BookStatus.Borrowed) {
return `❌ 《${book.title}》不是借阅状态,无法归还。`;
}
book.status = BookStatus.Available;
return `✅ 成功归还《${book.title}》!`;
}
// 显示所有图书
listBooks(): void {
console.log("\n📚 当前馆藏图书:");
console.table(this.books);
}
}
// --- 使用示例 ---
const lib = new Library();
lib.addBook("TypeScript 深入理解", "Agnes");
lib.addBook("JavaScript 高级程序设计", "Nicholas");
lib.listBooks();
console.log(lib.borrowBook(1));
console.log(lib.returnBook(2));
lib.listBooks();
运行方式:
ts-node library.ts
预期输出:
✅ 已添加新书:《TypeScript 深入理解》
✅ 已添加新书:《JavaScript 高级程序设计》
📚 当前馆藏图书:
┌─────────┬──────┬──────────────────────┬──────────────────────┬───────────┐
│ (index) │ id │ title │ author │ status │
├─────────┼──────┼──────────────────────┼──────────────────────┼───────────┤
│ 0 │ 1 │ 'TypeScript 深入理解' │ 'Agnes' │ 'avail...'│
│ 1 │ 2 │ 'JavaScript 高级...' │ 'Nicholas' │ 'avail...'│
└─────────┴──────┴──────────────────────┴──────────────────────┴───────────┘
✅ 成功借阅《TypeScript 深入理解》!
✅ 成功归还《JavaScript 高级程序设计》!
📚 当前馆藏图书:
┌─────────┬──────┬──────────────────────┬──────────────────────┬───────────┐
│ (index) │ id │ title │ author │ status │
├─────────┼──────┼──────────────────────┼──────────────────────┼───────────┤
│ 0 │ 1 │ 'TypeScript 深入理解' │ 'Agnes' │ 'borrow...'│
│ 1 │ 2 │ 'JavaScript 高级...' │ 'Nicholas' │ 'avail...'│
└─────────┴──────┴──────────────────────┴──────────────────────┴───────────┘
看,是不是很简单?这就是OOP(面向对象编程)的魅力,把数据和方法封装在一起。
八、 给新手的建议:如何持续进步?
- 不要怕报错:每一个红叉都是学习的机会。复制错误信息到搜索引擎,99%的问题别人也遇到过。
- 多敲代码:看懂不等于会写。一定要亲手输入每一行代码。
- 阅读优秀源码:去 GitHub 上看一些小型的、 starred 多的 TypeScript 项目,看看高手怎么组织代码。
- 保持好奇:TS的新特性每年都在更新,关注官方博客,了解最新特性如
const类型参数、satisfies操作符等。 - 加入社区:遇到卡点,去 Stack Overflow、V2EX、Reddit 的 r/typescript 问问,大家通常很乐意帮助新人。
结语
今天,我们从环境搭建开始,一路写到了第一个完整的类图书管理系统。你也许会觉得,这就是全部了吗?
不,这只是起点。
编程就像学一门新语言,一开始你只会说“你好”,但当你掌握了语法和词汇,你就能写出诗篇、小说、甚至戏剧。TS(或任何现代编程语言)就是你的词汇,而你的创意就是你的语法。
记住,每一个专家都曾是新手,每一个新手都曾对着红叉发呆。别让错误吓倒你,让它们成为你成长路上的垫脚石。
如果你在后续学习中遇到任何具体问题,欢迎随时回来问我。我会一直在这里,用我最多的知识和最热的心,为你解答。
现在,去打开你的编辑器,写下你的第二行代码吧!