第一个 TypeScript 程序
本教程共 80 篇 · 第 3 篇 · 更新于 2026-08-10 · 约 8 分钟阅读
本节目标:从头到尾走一遍「写 TS → 编译 → 运行」的完整闭环。学完你会写带类型注解的 TS 代码,用 tsc 把它编译成 JS,再用 Node.js 跑起来。
创建项目目录
先从终端开始。找个你喜欢的地方,新建一个文件夹:
mkdir my-first-ts
cd my-first-ts
这个文件夹就是咱们的第一个 TypeScript 项目了。先在里头初始化 npm(按回车一路默认就好):
npm init -y
然后在项目里安装 TypeScript 作为本地开发依赖:
npm install -D typescript
写第一行 TypeScript
在项目根目录下创建一个文件,名字叫 hello.ts。.ts 就是 TypeScript 的文件扩展名。
打开编辑器,往 hello.ts 里写这些内容:
// hello.ts —— 你的第一个 TypeScript 程序
function greet(name: string): string {
return `Hello, ${name}!`;
}
const user: string = "TypeScript";
const message: string = greet(user);
console.log(message);
别急着复制粘贴就跑——停下来看一眼这几行代码里多了什么。
类型注解长什么样
跟纯 JavaScript 相比,这里多了几个 : string。这就是 TypeScript 的类型注解(Type Annotation):
name: string— 告诉编译器,name这个参数必须是字符串: string在greet函数末尾 — 告诉编译器,这个函数必须返回一个字符串const user: string— 声明user是一个字符串类型的常量
这些注解在编译之后会被完全擦除,不会留在最终的 JS 文件里。它们只存在于编译阶段,是给编译器和 IDE 看的。
编译:把 TS 变成 JS
回到终端,在项目根目录下运行:
npx tsc hello.ts
如果一切正常,终端不会有任何输出——这在命令行世界里通常意味着”没有错误”。如果你看到了错误信息,回头检查一下 hello.ts 里的内容是否完全一样。
编译成功后,当前目录下会多出一个文件:hello.js。这就是 tsc 的编译产物。
看看编译后的 JS 长什么样
打开 hello.js,你会看到类似这样的内容:
// hello.js —— 编译产物
function greet(name) {
return `Hello, ${name}!`;
}
const user = "TypeScript";
const message = greet(user);
console.log(message);
注意几个变化:
- 类型注解全没了。
: string消失得干干净净——编译后的 JS 就是纯 JavaScript,没有一丁点类型信息。 - 模板字符串和
const原样保留。因为 TypeScript 7.0 的target最低支持 ES2015,原生支持模板字符串和const,所以不需要降级处理。 - 编译产物跟源码几乎一样,只是去掉了类型注解。这就是 TS 7.0 默认行为——你写什么,JS 就输出什么(除了类型注解)。
这就是 TypeScript 的一个核心承诺:编译之后的代码就是标准 JavaScript,可以在任何 JS 环境里跑,不需要额外的运行时库。
运行编译产物
用 Node.js 跑一下编译后的 JS:
node hello.js
你应该看到:
Hello, TypeScript!
成功了!你刚刚完成了一个完整的 TypeScript 开发流程:写 .ts → tsc 编译 → node 运行产出。
故意写错试试
TypeScript 最有价值的地方就是能在你跑代码之前告诉你哪里写错了。我们来故意制造一些问题:
// 把 user 改成数字
const user: string = 123;
保存后重新编译:
npx tsc hello.ts
你会看到类似这样的错误:
hello.ts:6:7 - error TS2322: Type 'number' is not assignable to type 'string'.
这条错误信息告诉你:第 6 行,你声明了 user 是 string 类型,但给它赋了一个 number 值。这两个类型不兼容。
关键点来了——即使有错误,hello.js 依然会被生成出来。TypeScript 默认不阻止编译产出,它只是提醒你。如果你想让”有错就不产出”,后面讲 tsconfig.json 时会说到 noEmitOnError 选项。
不用注解行不行
TypeScript 有个很聪明的能力:类型推断。很多情况下你根本不需要手动写类型注解:
// 不用注解,TypeScript 照样知道类型
let count = 0; // TS 推断为 number
let name = "TypeScript"; // TS 推断为 string
let flag = true; // TS 推断为 boolean
但是函数的参数一般建议写注解。因为调用方没法从参数值推断出类型——参数的类型信息只能靠你明确告诉编译器。
// 好:参数有注解
function add(a: number, b: number): number {
return a + b;
}
// 不好:a 和 b 都是 any,等于没检查
function add(a, b) {
return a + b;
}
一个好的经验法则:函数参数写注解,函数体内的变量和返回值大多数情况交给推断就好。
小结
你刚刚完成了从零到”写出并运行第一个 TypeScript 程序”的全过程。核心流程就是三个步骤:写 .ts → npx tsc 编译 → node 运行产出的 .js。
类型注解是你的朋友,但它只活在编译阶段。就像施工时的脚手架——盖楼的时候离不开,楼盖好了就拆走,不留在最终交付的房子里。
下一章,我们来深入 tsc 编译器本身,看看它除了最简单的编译,还能做什么。