01 · NOTES / WebGIS 开发
第 20 节 · 基础类型标注
2026 年 9 月 1 日
第 20 节 · 基础类型标注
📌 版本信息:基于 TypeScript 5.x(基础类型系统多年稳定;2026-08-29 核对) 📚 来源:TS 官方手册 · 日常类型 | 阮一峰 TS 教程 · 类型
一、这一节的目标
- 标注原始类型:string / number / boolean
- 标注数组与对象(两种写法)
- 理解联合类型与类型收窄
- 分清
any/unknown/void/null相关标注 - 能给一份真实 GIS 数据(GeoJSON 片段)标全类型
二、原始类型与数组
// ── 原始类型:小写开头(行业规范,别用大写 String)──
const name: string = '武汉';
const lat: number = 30.5929;
const visible: boolean = true;
// ── 数组:两种等价写法 ──
const coords: number[] = [114.3052, 30.5929]; // 推荐
const coords2: Array<number> = [114.3052, 30.5929]; // 等价(泛型写法,下节展开)
// 元素可以是联合类型
const mixed: (string | number)[] = ['武汉', 30.59, '114.3'];
// 元组 Tuple:定长、每位类型可不同——坐标的最佳表达!
const point: [number, number] = [114.3052, 30.5929]; // GeoJSON coordinates
point.push(3.14); // ⚠️ 历史包袱:push 能绕过长度限制,读 [2] 时 TS 会警告
💡 GIS 记忆点:
[number, number]元组天然表达"经纬度对",比number[]更精确——长度锁死为 2。
三、对象类型:两种写法
// 写法 ①:内联类型(匿名,一次性使用)
let city: { name: string; lat: number; lng?: number } = { name: '武汉', lat: 30.59 };
// lng?:可选属性(值可以是 undefined,且可以不写这个键)
// 写法 ②:type 起个名字(复用,推荐——第 21 节展开 interface)
type City = {
name: string;
lat: number;
lng?: number; // 可选
readonly id: number; // 只读:赋值后不可再改
};
const wh: City = { id: 1, name: '武汉', lat: 30.59 };
// wh.id = 2; // ❌ Cannot assign to 'id' because it is a read-only property
属性访问时的 TS 帮助:只允许访问声明过的属性——wh.pop 直接红线(JS 里默默 undefined,TS 当场抓)。
四、联合类型:多种可能
// 竖线 | :值可以是其中任意一种
type MapProvider = 'osm' | 'tianditu' | 'gaode'; // 字面量联合:锁死取值范围!
let provider: MapProvider = 'osm';
provider = 'gaode'; // ✅
provider = 'baidu'; // ❌ 不能赋非列表值——"枚举感"白嫖,不用记数字常量
// 函数参数的联合:处理时要"收窄"(narrowing)
function formatId(id: string | number): string {
// if (typeof id === 'string') 分支里,TS 知道 id 是 string,能调 toUpperCase
if (typeof id === 'string') {
return id.toUpperCase();
}
return id.toString(); // 这个分支里 TS 知道 id 是 number
}
类型收窄(narrowing):TS 跟踪你的运行时判断(typeof / === / in 等),在分支内自动缩小类型范围。这是 TS 最聪明的能力,读代码时注意体会。
五、特殊类型
let a: any; // 关闭检查:啥都能装、啥都能干——"逃生舱",新代码禁止随手用
let u: unknown; // 更安全的 any:啥都能装,但用之前必须先收窄
// (外部数据的初始形态用它,验完再当具体类型用)
function log(msg: string): void { // void:没有返回值
console.log(msg);
}
function fail(): never { // never:永远不会正常返回(总是抛错/死循环)
throw new Error('boom');
}
// 与 null 相关:strictNullChecks 开启时(默认开启),null/undefined 不能随便赋给别的类型
const el: HTMLElement | null = document.querySelector('#app');
el.innerHTML = 'hi'; // ❌ Object is possibly 'null'
if (el) el.innerHTML = 'hi'; // ✅ 收窄后安全——它逼你处理"找不到元素"的情况
// 常用简写:el!.innerHTML(非空断言:我保证不是 null——确认没问题时用,别滥用)
✍️ 规范:
any是"我要撒谎"(明知有错别抓我),unknown是"我还不知道"(验完再说)。项目规范一般禁止 any(ESLint 能强制)。
六、动手跟练:20 · 类型标注练习
配套文件:02-web-basics/examples/20-类型标注练习.html(纸上题 + Playground 验证清单)
步骤:
- 打开文件,20 道标注题分五组:原始类型、数组元组、对象与可选、联合与收窄、综合实战
- 每组先纸上写答案,再去 TypeScript Playground 贴进去验证(记得开 Strict 模式)
- 综合实战题:给一份 8 行的迷你 GeoJSON 标全类型(这是 C-02b 项目 data.ts 的雏形)
通关标准:
- 20 题正确率 ≥ 18
- 能说出元组和普通数组的区别
- 综合实战题的 GeoJSON 类型定义能通过 Playground 编译
七、自测题
string和String哪个对?为什么?[number, number]与number[]的区别?哪个更适合表达坐标?lng?: number中的?是什么意思?any和unknown的核心区别?document.querySelector返回HTMLElement | null,TS 为什么这样设计?
参考答案
- 小写
string。大写String是包装对象类型,行为怪异,规范禁用。 - 元组定长且逐位定类型;数组不定长同类型。坐标用元组(长度 2 锁死)。
- 可选属性:该键可缺席;类型自动变成
number | undefined。 - any 关闭所有检查随便用;unknown 接受任何值但使用前必须收窄验证。
- 因为选择器可能匹配不到(返回 null),TS 逼你在使用前判空——把运行时 NPE 提前变成编译期问题。
八、下一步
单点类型会标了 → 第 21 节:interface 与 type,学"给数据形状起名字"的两种官方姿势。
TAGSweb