TypeScript 是 JavaScript 的一个超集,添加了类型系统和编译期错误检查等功能 => 静态类型检查。
类型指的是一组具有相同特征的值。
静态类型系统描述了运行程序时的值的形状和行为。
TypeScript 支持块级类型声明,即类型可以声明在代码块(用大括号表示)里面,只在当前代码块有效。
动态类型 pk 静态类型
JavaScript 动态类型语言,没有使用限制。
let test = 'ligang'
test = 33
TypeScript 静态类型语言,引入了类型系统。
let test: string = 'ligang'
test = 33 // 不能将类型“number”分配给类型“string”
特性 | JavaScript | TypeScript |
---|---|---|
类型系统 | 动态类型 | 静态类型 |
编译 | 解释执行,无需编译 | 需要编译成 JavaScript |
工具支持 | 广泛支持,无需额外配置 | 需要配置 TypeScript 编译器和类型定义 |
错误检测 | 运行时错误检测 | 编译时错误检测 |
代码维护 | 较难维护大型项目 | 易于维护大型项目 |
学习曲线 | 简单,易于上手 | 需要额外学习类型系统 |
库和框架 | 几乎所有库和框架都支持 | 需要类型定义文件(或自行定义) |
性能 | 无额外开销 | 编译过程可能引入微小延迟 |
兼容性 | 无需转换,直接运行 | 需要编译成 JavaScript 才能运行 |
社区和生态系统 | 非常成熟和广泛 | 正在快速发展,但不如 JavaScript 成熟 |
开发体验 | 快速开发和迭代 | 提供更好的开发体验,如智能提示和重构工具 |
未来兼容性 | 随着 ECMAScript 的更新而更新 | 需要更新 TypeScript 以支持新特性 |
💡 TypeScript 本身不执行任何代码,只是添加了一个类型系统,用于在编译时提供类型安全和错误检查。TypeScript 的代码最终需要被编译成 JavaScript,然后由 JavaScript 引擎执行!
类型声明
在标识符后面添加“冒号 + 类型”。
let test: string = 'ligang' function toString(num: number): string {return String(num);
}
类型声明并不是必需的,如果没有,TypeScript 会自行推断类型。
由于这个原因:所有 JavaScript 代码都是合法的 TypeScript 代码。这样设计还有一个好处,将以前的 JavaScript 项目改为 TypeScript 项目时,可以逐步地为老代码添加类型。1
基本类型
TypeScript 继承了 JavaScript 的类型设计:boolean、string、number、bigint、symbol、object、undefined、null
。
值类型
单个值的情况,称为“值类型”。
let myName: 'ligang';myName = 'ligang';
myName = '李刚'; // 不能将类型“"李刚"”分配给类型“"ligang"”。
上述示例,myName
的类型是字符串 ligang
。后续只能赋值为 ligang
,赋值为其他字符串就会报错。
使用 let/const
声明的变量,如果没有注明类型,就会推断该变量是值类型。
let myName = 'ligang';
myName = true; // 不能将类型“boolean”分配给类型“string”
⚠️ 如果赋值为对象,会推断既有属性。
const a = { b: 1 };
a.b = '1'; // 不能将类型“string”分配给类型“number”。
any|never|unkown
值 | 说明 |
---|---|
any | 表示没有任何限制,可以赋予任意类型的值 |
unkown | 表示任何值,可以赋值为各种类型的值;只有明确unknown 变量的实际类型,才允许使用它 |
never | 表示空,不包含任何值,可以赋值给任意其他类型 |
any 类型
只有为了适配老的 JavaScript 项目,让代码快速迁移到 Typescript, 可以把变量设置为 any
,其他场景应该尽量避免使用 any
类型。
unkown 类型
所有类型的值都可以分配给 unknown
类型;但只有明确 unknown
变量的实际类型,才允许使用它。
let a: unknown = 1;r1 = a + 10; // “a”的类型为“未知”if (typeof a === 'number') {r2 = a + 10; // 正确
}
never 类型
使用 never
类型来表示不应该存在的状态。
function getArea(shape: Shape) {switch (shape.kind) {...default: {const _exhaustiveCheck: never = shape;return _exhaustiveCheck;}}
}
在新追加类型时,会凸显其作用:在开发阶段就提前警示可能的错误。
type Shape = Circle | Square | { kind: 'triangle'; sideLength: number };function getAre(shape: Shape) {...default: {const _exhaustiveCheck: never = shape; // 不能将类型“{ kind: "triangle"; sideLength: number; }”分配给类型“never”return _exhaustiveCheck;}
}
💯 TypeScript 有两个“顶层类型”(any
和 unknown
),但是“底层类型”只有 never
。
- 顶层类型:包含了一切可能的类型;所有其他类型的全集。
- 底层类型:任何类型都包含的类型;空集是任何集合的子集。
联合类型
多个类型组成的一个新类型,使用符号 |
表示。 表示一个值可以是几种类型之一!
let myName: 'ligang' | '李刚';
interface ViolationItem {violationCode: string | null;violationName?: string;
}
如果一个变量有多种类型,读取该变量时,往往需要进行==“类型缩小”==2,区分该值到底属于哪一种类型,然后再进一步处理。
“类型缩小”是 TypeScript 处理联合类型的标准方法,凡是遇到可能为多种类型的场合,都需要先缩小类型,再进行处理!
function getViolationCode (data: ViolationItem) {if (typeof data.violationCode === "string") {return data.violationCode.toLowerCase()} else {return data.violationCode}
}
交叉类型
多个类型组成的一个新类型,使用符号 &
表示。表示一个值同时具有所有这些类型的属性!
A & B
同时满足 A
和 B
。交叉类型常常用来为对象类型添加新属性。
interface Person {name: string;
}type PersonType = Person & { age: number };
PersonType
是交叉类型,在 Person
基础上追加了属性 age
。
type 用来定义一个类型的别名「下篇博文详细介绍」。
🍒 interface 扩展常用 extends
实现!type 的扩展使用交叉类 &
!
https://typescript.p6p.net/typescript-tutorial/basic.html ↩︎
https://nodejs.cn/typescript/handbook/narrowing ↩︎