返回笔记列表
01 · NOTES / WebGIS 开发

第 20 节 · 基础类型标注

2026 年 9 月 1 日

第 20 节 · 基础类型标注

📌 版本信息:基于 TypeScript 5.x(基础类型系统多年稳定;2026-08-29 核对) 📚 来源:TS 官方手册 · 日常类型阮一峰 TS 教程 · 类型

一、这一节的目标

  1. 标注原始类型:string / number / boolean
  2. 标注数组与对象(两种写法)
  3. 理解联合类型与类型收窄
  4. 分清 any / unknown / void / null 相关标注
  5. 能给一份真实 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 验证清单)

步骤:

  1. 打开文件,20 道标注题分五组:原始类型、数组元组、对象与可选、联合与收窄、综合实战
  2. 每组先纸上写答案,再去 TypeScript Playground 贴进去验证(记得开 Strict 模式)
  3. 综合实战题:给一份 8 行的迷你 GeoJSON 标全类型(这是 C-02b 项目 data.ts 的雏形)

通关标准:

  • 20 题正确率 ≥ 18
  • 能说出元组和普通数组的区别
  • 综合实战题的 GeoJSON 类型定义能通过 Playground 编译

七、自测题

  1. stringString 哪个对?为什么?
  2. [number, number]number[] 的区别?哪个更适合表达坐标?
  3. lng?: number 中的 ? 是什么意思?
  4. anyunknown 的核心区别?
  5. document.querySelector 返回 HTMLElement | null,TS 为什么这样设计?

参考答案

  1. 小写 string。大写 String 是包装对象类型,行为怪异,规范禁用。
  2. 元组定长且逐位定类型;数组不定长同类型。坐标用元组(长度 2 锁死)。
  3. 可选属性:该键可缺席;类型自动变成 number | undefined
  4. any 关闭所有检查随便用;unknown 接受任何值但使用前必须收窄验证。
  5. 因为选择器可能匹配不到(返回 null),TS 逼你在使用前判空——把运行时 NPE 提前变成编译期问题。

八、下一步

单点类型会标了 → 第 21 节:interface 与 type,学"给数据形状起名字"的两种官方姿势。

TAGSweb