青戈AI小栈
会员限时8折
TypeScript 入门到项目开发

创建 TypeScript 项目,显示第一件商品

7,432 字约 19 分钟读完21 次阅读更新于 2026/10/22

登录后收藏

阅读设置

字号
行距
代码

这门课面向第一次学习 TypeScript 的开发者。从创建项目开始,逐步学习怎样描述数据、检查函数调用、组织模块和处理接口响应。学习的目标是:面对一个业务需求,能够设计合适的数据类型,实现功能,并根据类型提示和运行结果定位问题。

课程从简单的页面逐步推进到完整功能。每引入一种写法,都会结合代码解释它的作用、为什么需要它,以及怎样核对结果;常见错误也会配合具体提示说明原因,帮助你理解类型检查能够发现什么、哪些问题仍需要程序在运行时处理。

贯穿课程的案例是一个商品管理页面。随着学习进度,逐步加入列表展示、库存调整、表单和分类管理,再接入课程提供的接口服务。接口部分重点学习前端怎样获取、校验和提交数据,不讲后端服务开发。

本节先完成第一步:创建并启动 TypeScript 项目,让浏览器显示商品名称,再运行类型检查,对照一次错误赋值,观察类型检查结果与页面运行之间的区别。

开始前需要会什么

“入门”指 TypeScript 开发入门,不要求学过 React 或 Vue。开始前需要了解:

  • HTML 的标题、段落和页面基本结构。
  • CSS 的选择器、颜色、字体及内外边距。
  • JavaScript 的变量、对象、数组、函数和属性访问。

TypeScript、Vite 和 Node.js 各自负责什么

TypeScript 是在 JavaScript 基础上增加类型语法的语言。例如,可以约定商品名称是字符串;把数字填到该位置时,类型检查工具就能报告不符合约定的地方。已有的 JavaScript 基础仍会用到,类型标注的具体写法在本节代码中介绍。查阅语言手册时,可以从 TypeScript 官方中文文档 进入;部分条目仍为英文。

Vite 提供开发服务器和构建工具。开发时,它将项目源码处理成浏览器可以执行的 JavaScript;保存文件后,页面可以随之更新。本课程使用它创建和运行 TypeScript 项目。

Node.js让 JavaScript 可以在浏览器之外运行,本节用它运行 Vite 和 TypeScript 检查工具。随 Node.js 安装的npm 用来下载项目依赖、执行项目命令。

开发服务和类型检查分别负责页面运行与类型错误报告,启动开发服务不会自动完成类型检查。本节会分别运行这两项操作,并对照它们的结果。

安装并检查开发工具

以下步骤使用 Windows 10/11、VS Code 和命令提示符终端。macOS、Linux 的项目命令相同,安装 Node.js 时选择对应系统的版本;项目目录可使用主目录下的 Course,不照抄 Windows 的磁盘路径。

安装 Node.js 与 VS Code

从 Node.js 官方下载页 下载 Node.js 24 LTS 的安装程序。Windows 普通 Intel/AMD 电脑选择 x64,ARM 电脑选择 ARM64,按向导安装并保留 npm 与添加到 PATH 的选项。

PATH 是系统查找命令的目录列表,安装时添加到 PATH 后,终端才能找到 node 和 npm。

从 VS Code 官方下载页(英文) 下载并安装编辑器。安装 Node.js 后重新打开 VS Code,使新终端读取更新后的 PATH。

本节实测使用 Node.js 24.16.0、npm 11.13.0。Vite 官方要求 Node.js 20.19+ 或 22.12+,Node.js 24 LTS 满足要求;已有 Node.js 时先检查版本,再决定是否重装。要求来源见 Vite 官方中文入门文档。

选择终端并查看版本

在 VS Code 中按 Ctrl+Shift+P 打开命令面板,输入 Terminal: Select Default Profile,选择 Command Prompt(命令提示符)。再通过 Terminal > New Terminal 新建终端。

这里使用命令提示符,是为了避免 Windows 的 PowerShell 脚本执行策略阻止 npm 启动。选择默认终端不会改变已经打开的终端,需要新建一个。后续 Windows 命令都在这个终端里执行,无需调整系统执行策略。

逐条执行:

shell
node --version
npm --version

本节验证环境分别输出:

输出
v24.16.0
11.13.0

如果提示不是内部或外部命令,先关闭并重新打开 VS Code;仍然失败时,重新运行 Node.js 安装程序,确认安装了 npm 并添加到 PATH。

创建 TypeScript 项目

生成项目文件

在 Windows 文件资源管理器中新建存放课程工程的文件夹,例如 D:\Course。没有 D 盘时选择其他位置;不要在现有业务项目里面创建课程工程。

在 VS Code 中选择 File > Open Folder,打开 Course 文件夹,再新建命令提示符终端。确认终端当前目录是刚打开的文件夹,在这里执行:

shell
npx --yes create-vite@9.2.1 ts-demo --template vanilla-ts --no-interactive

这条命令会在当前目录下新建 ts-demo:

  • npx 负责运行项目创建工具;--yes 表示允许下载并运行命令中指定版本的工具。
  • create-vite@9.2.1 是工具名称和版本,不是 TypeScript 或 Vite 的版本。
  • ts-demo 是新项目的文件夹名。
  • --template vanilla-ts 选择不带前端框架的 TypeScript 模板。
  • --no-interactive 按指定模板创建,不进入框架选择问答。

创建完成后,左侧出现 ts-demo 文件夹,终端提示进入目录、安装依赖和启动服务。接下来通过 VS Code 打开这个新目录,不在 Course 中执行项目命令。

如果已有同名文件夹,先核对是不是此前创建的课程项目。已有项目可以直接打开,不要选择清空包含自己文件的目录。

固定依赖并安装

选择 File > Open Folder,打开刚创建的 ts-demo 文件夹,例如 D:\Course\ts-demo;使用其他磁盘或目录时,以实际创建位置为准。左侧顶层目录应变成 ts-demo,其中能看到 package.json。新建终端,后续命令都在这个项目根目录执行。

package.json 记录项目名称、命令和依赖。为了使用本节实际验证的版本,将它的全部内容替换为:

json
{
  "name": "ts-demo",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "check": "tsc --noEmit",
    "build": "tsc && vite build",
    "preview": "vite preview"
  },
  "devDependencies": {
    "typescript": "6.0.3",
    "vite": "8.3.4"
  }
}

本节先使用 dev 和 check:前者启动开发服务,后者检查类型。devDependencies 中的两个包都是开发工具;type: "module" 指定项目使用模块方式组织代码,暂时保留即可。

保存文件,在终端执行:

shell
npm install

等待命令完成、终端重新出现可输入命令的提示符。安装后会生成 node_modules 和 package-lock.json:前者保存依赖代码,后者记录实际安装的版本,后续保留锁文件,不手动修改依赖目录。

启动并打开页面

在项目根目录执行:

shell
npm run dev

npm run dev 读取 package.json 的 scripts.dev,执行其中的 vite,启动开发服务。

终端显示启动信息后,在 Chrome 或 Edge 中打开 Local 一行给出的地址。默认端口未被占用时通常是:

输出
http://localhost:5173/

当前模板页面包含 TypeScript、Vite 标识、Get started 标题和计数按钮。看到它说明模板能运行;接下来把它换成商品页面。

localhost 表示当前电脑,端口号用于区分服务。默认端口被占用时,Vite 会尝试其他端口,以终端显示的地址为准,不要双击 index.html。

服务启动后,这个终端会持续显示运行信息,暂时保留它。后面执行类型检查时,再新建第二个终端。

显示第一件商品

页面部分修改三个文件:

文件 用途
src/main.ts 创建页面元素,写入商品名称
index.html 页面入口,加载 src/main.ts
src/style.css 设置页面的通用样式

文件名中的 .ts 表示 TypeScript 源码。下面在 JavaScript 的变量定义中加入一处类型标注,再用 DOM 操作创建页面元素。

直接在 index.html 中写 <p>矿泉水</p> 也能显示商品名称。后面商品会变成一组数据,需要由代码按数据生成页面,因此从本节开始就把内容交给 main.ts 创建。

编写 main.ts

将 src/main.ts 的全部内容替换为:

typescript
import './style.css'

const productName: string = '矿泉水'

const page = document.createElement('main')
page.className = 'page'

const title = document.createElement('h1')
title.textContent = '商品管理'

const productNameElement = document.createElement('p')
productNameElement.textContent = productName

page.append(title, productNameElement)
document.body.append(page)

保存后,原来的模板内容被移除,页面出现“商品管理”和“矿泉水”,位置和颜色暂时仍受模板样式影响。下面先看新增代码负责什么,再替换入口和样式。

import './style.css' 加载同目录的样式文件,./ 表示当前文件所在目录。

const productName: string = '矿泉水' 定义商品名称。冒号后的 string 是类型标注,表示这里约定保存字符串;等号右侧是实际的值。删去 : string 仍然可以运行,TypeScript 会根据初始值推断类型,本节保留标注以便观察检查结果。

浏览器用 DOM 对象表示页面元素。这里使用几个基本操作:

  • document.createElement('main') 创建一个 main 元素,返回它对应的对象。创建后还没有放到页面上。
  • className = 'page' 为它设置 CSS 类名,对应 HTML 中的 class="page"。
  • createElement('h1') 和 createElement('p') 创建标题与段落,保存到各自的变量中。
  • textContent 设置元素中的文字。商品名称按文字显示,不把其中的内容解析成 HTML 标签。
  • page.append(title, productNameElement) 将标题和段落按顺序放入主体;document.body.append(page) 再把主体放入页面。

main 表示页面主要内容,h1 是内容标题,p 是段落。只创建对象而不调用 append,元素不会出现在页面里。用变量保留元素,是为了接着设置文字、类名和放置位置。

替换页面入口

将项目根目录 index.html 的全部内容替换为:

html
<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>商品管理</title>
  </head>
  <body>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

lang="zh-CN" 声明页面语言,charset="UTF-8" 指定字符编码,title 设置浏览器标签页名称。viewport 让移动端按设备宽度显示。

script 指向刚修改的 src/main.ts;type="module" 使脚本按模块方式加载,可以使用 import。这个脚本通过 Vite 开发服务处理后才交给浏览器,不是要求浏览器直接理解 TypeScript 类型语法。

body 中没有手写标题和段落,因为它们由 main.ts 创建。模板里原有的空容器和图标引用在这份入口中已经不再使用。

替换模板样式

将 src/style.css 的全部内容替换为:

css
* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: #f5f6f8;
  color: #1f2937;
  font-family: Arial, "Microsoft YaHei", sans-serif;
  line-height: 1.6;
}

.page {
  max-width: 720px;
  margin: 40px auto;
  padding: 24px;
  background: #fff;
}

.page h1 {
  margin: 0 0 16px;
  font-size: 24px;
}

.page p {
  margin: 0;
}

body 设置整页背景、文字与字体;.page 对应 main.ts 中的类名,在浅灰背景上显示白色内容区,限制宽度并居中。padding 留出内部间距,margin 留出外部间距。其余选择器分别调整标题和段落。

三个文件都保存后,浏览器标签页标题为“商品管理”,页面显示:

输出
商品管理
矿泉水

模板中的 src/counter.ts、src/assets/ 和 public/ 资源本节不需要使用,可以先保留;新的 main.ts 已经不再导入计数器和标识图片。

单独运行类型检查

明确开启严格检查

tsconfig.json 是 TypeScript 的配置文件。TypeScript 的检查与编译工具 tsc 读取它,决定检查哪些文件、采用哪些类型检查规则。配置文件的作用见 TypeScript 官方中文文档:tsconfig.json 是什么。

打开项目根目录的 tsconfig.json,找到 "compilerOptions": {,在它下一行加入 "strict": true,,其余模板配置保留原样。如果已经存在 strict,就将它的值设为 true,不重复添加同名选项。

strict 开启一组更严格的类型检查。这里先固定项目的检查方式,不逐项修改模板配置;配置的详细含义在用到对应问题时再说明。

检查当前代码

保留运行 Vite 的终端,通过 Terminal > New Terminal 新建第二个命令提示符终端,确认当前目录仍为 ts-demo。执行:

shell
npm run check

它会运行 package.json 中的 tsc --noEmit,其中 --noEmit 表示只检查、不生成输出文件。

当前代码通过时,终端显示脚本名称和执行命令,然后回到可输入命令的提示符,不额外输出“检查成功”:

输出
> ts-demo@0.0.0 check
> tsc --noEmit

这次检查读取 tsconfig.json 中配置的源码范围,不只检查编辑器当前打开的文件。

对照一次类型错误

在 src/main.ts 中,只把定义 productName 的这一行改为下面的内容,其余代码不动并保存:

typescript
const productName: string = 100

数字 100 不符合 string 的约定。再次在第二个终端执行 npm run check,本节环境得到的核心错误为:

输出
error TS2322: Type 'number' is not assignable to type 'string'.

终端同时给出 src/main.ts 的行列位置;不同版本的显示排版可能有差异。VS Code 的 TypeScript 提示通常也会给这一行加红色波浪线,鼠标悬停可以查看原因。

此时浏览器显示 100,页面没有类型错误覆盖层。刷新页面后也仍能运行:Vite 的开发服务将项目源码处理成浏览器可以执行的 JavaScript,不代替刚才的类型检查;处理后的代码不再包含类型标注,因此不会在运行时按 string 的约定检查这个值。这里的数值在赋给 textContent 时被浏览器转成了文字,所以看到了 100。

如果页面没有更新,先确认开发服务仍在运行、文件已经保存,再刷新页面。

因此,页面能打开不能证明类型检查已经通过,红线也不是浏览器替程序拒绝了这个值。类型检查与生成 JavaScript 的区别见 TypeScript 官方中文手册:基础;Vite 的处理方式见 Vite 官方中文文档:TypeScript。

核对后,把这一行恢复为:

typescript
const productName: string = '矿泉水'

保存,再执行 npm run check,确认检查通过,页面恢复“矿泉水”。不通过时先检查终端给出的文件位置,不要改掉类型标注来绕过这次错误。

启动或显示不符合预期时

npm 提示脚本被禁止运行

这通常表示当前打开的仍是 PowerShell。按开头的步骤将默认终端选为 Command Prompt,再新建终端,在 ts-demo 根目录重试 npm 命令。已有终端不会因更改默认选项自动变成命令提示符。

提示找不到 package.json 或脚本

先看终端当前目录,应该是项目根目录 ts-demo,不是上一级 Course,也不是 src。通过 VS Code 打开正确文件夹并新建终端,再检查 package.json 的 scripts 中有 dev 和 check。首次安装失败时,先恢复网络并重新执行 npm install。

仍然显示模板或旧内容

确认改的是当前项目的 src/main.ts 和 src/style.css,文件已经保存,浏览器地址与运行终端的 Local 地址一致。存在多个开发服务时,不要仅凭端口习惯判断打开了哪一个项目;仍有疑问时刷新页面。

有商品标题,却看不到商品名称

核对 productNameElement.textContent = productName 和 page.append(title, productNameElement) 是否都保留。前者写入文字,后者把段落放到主体中;只创建元素不会自动显示。

连续核对项目运行

  1. 确认 main.ts 中的 productName 为字符串“矿泉水”,执行 npm run check,没有类型错误。
  2. 保持开发服务运行,把这一行的名称改为“可乐”并保存。不手动刷新,确认页面更新为“可乐”,再恢复“矿泉水”。
  3. 在运行 Vite 的终端按 Ctrl+C 停止服务;Windows 若询问是否终止批处理任务,输入 Y 并回车。刷新浏览器,确认原服务地址已经不能加载页面。
  4. 在该终端重新执行 npm run dev,按终端显示的 Local 地址打开,确认“商品管理”和“矿泉水”恢复显示。
  5. 再执行一次 npm run check,确认检查通过,并保留当前项目供下一节使用。
有帮助
登录后提问 / 纠错

提问与反馈

仅你和管理员可见。我的反馈

设置你的昵称

在英雄榜和讨论中,使用你自己的名字。

2–12 个字符0 / 12