在当今前端开发领域,TypeScript已经成为提升代码质量和开发效率的必备技能。本教程专为TypeScript新手打造,从最基础的环境搭建开始,循序渐进地讲解类型系统、接口、泛型等核心概念,同时配合丰富的代码示例帮助你快速掌握。无论你是想提升代码健壮性的JavaScript开发者,还是准备学习Angular、Vue3或React的前端新人,这份完整指南都将帮助你建立坚实的TypeScript基础,避开常见陷阱,让你的开发之路更加顺畅。
一、TypeScript 介绍
TypeScript 简称『TS』,是微软开发的一个开源的编程语言。它是 JavaScript 的超集,为 JS 添加了静态类型定义功能。TypeScript 不仅支持 ES6、ES7 等规范,而且通过类型系统提供了更强大的工具支持,极大地提高了开发效率和代码质量。
二、TS 特点
TS 主要有如下几个特点:
- 🔄 完全兼容 JavaScript:是 JavaScript 的超集,任何现有的 JS 程序都是合法的 TS 程序
- 🛡️ 引入类型系统:可以尽早的定位错误位置, 帮助提升开发效率,增强代码可靠性
- ⚡ 先进的 JavaScript:支持 JavaScript 的最新特性,提前使用 ECMAScript 的新特性
- 🔧 强大的工具支持:智能提示、代码补全、重构等 IDE 功能更加强大
- 🏢 企业级应用:适用于大型项目,有助于团队协作和代码维护
💡 为什么选择TS:TypeScript 在社区的流行度越来越高,它非常适用于一些大型项目,也非常适用于一些基础库,极大地帮助我们提升了开发效率和体验。Angular、Vue3、React 等主流框架都采用了 TypeScript 构建。
三、TS 环境搭建
学习 TS 阶段我们可以借助 TypeScript 的编译工具『typescript』
npm i -g typescript
使用下面的命令检查是否安装成功以及查看包的版本
tsc -v
四、TS 初体验
-
typescript 初始化. 创建 ts 的配置文件
tsconfig.json
tsc --init
-
创建一个 JS 文件 『hello.ts』
let str: string = 'hello world';
console.log(str);
function add(a: number, b:number):number{
return a + b;
}
console.log(add(1, 100)); -
命令行运行,
这里的后缀是 ts
tsc hello.ts
-
命令行运行,
这里的后缀是 js
node hello.js
🔍 提示:可以使用
tsc -w
命令开启自动编译
五、TS 语法
5.1 TS 基础类型
TypeScript 支持与 JavaScript 几乎相同的数据类型,此外还提供了实用的枚举类型方便我们使用
TS 支持的变量类型如下:
类型 | 描述 |
---|---|
boolean | 限制为布尔类型, true 或者 false |
number | 限制为任意的数字。 二进制,八进制,十进制,十六进制均可 |
string | 限制为任意的字符串。单引号,双引号,反引号均可 |
字面量 | 限制为某个字面量 |
any | 限制为任意类型 |
unknown | 类型安全的any |
void | 限制为 undefined, 一般用来限制函数的返回值 |
never | 表示永不可能有返回值的类型 |
object | 限制为对象类型 |
array | 限制为数组类型 string[] Array<number> |
tuple 元组 | 限制为固定长度与类型的数组 |
enum 枚举 | 限制为枚举的数据 |
5.1.1 布尔类型
最基本的数据类型就是简单的 true/false 值,在JavaScript 和 TypeScript 里叫做 boolean
(其它语言中也一样)。
let isDone: boolean = false;
isDone = true;
// isDone = 2 // error
5.1.2 数字类型
除了支持十进制和十六进制字面量,也支持二进制和八进制字面量。
let a1: number = 10 // 十进制
let a2: number = 0b1010 // 二进制
let a3: number = 0o12 // 八进制
let a4: number = 0xa // 十六进制
5.1.3 字符串类型
JavaScript 程序的另一项基本操作是处理网页或服务器端的文本数据。 像其它语言里一样,我们使用 string
表示文本数据类型。 和 JavaScript 一样,可以使用双引号("
)或单引号('
)表示字符串。
let name:string = 'tom'
name = 'jack'
// name = 12 // error
let age:number = 12
const info = `My name is ${name}, I am ${age} years old!`
5.1.4 字面量类型
TS 允许限制某个变量为固定的某个值
let z: 521 = 521;
let z2: 'love' = 'love';
// z='abc'; //类型不符 error
// 联合类型
let gender: '男' | '女';
gender = '男';
gender = '女';
// gender = '未知'; // error
5.1.5 any 类型
any 类型允许变量的值为任意类型, 并且可以进行任意类型的赋值
let a: any = 100;
a = 'iloveyou';
a = true;
a = [1, 2, 3];
// 隐式any,声明变量不指定类型且不初始化
let something;
something = 100;
something = '你好';
尽量不要用 any, 因为对于 any 类型 typeScript 会关闭类型检查功能
5.1.6 unknown 类型
unknown
是 TypeScript 3.0 引入的新类型,它是 any
类型对应的安全类型。
let notSure: unknown = 4;
notSure = "hello";
notSure = [];
// unknown比any更安全 - 不能直接赋值给其他类型
let s: string;
// s = notSure; // 错误:不能将类型"unknown"分配给类型"string"
// 需要先进行类型检查或类型断言
if (typeof notSure === "string") {
s = notSure; // 正确:经过类型检查
}
// 类型断言
s = notSure as string; // 或 s = <string>notSure;
5.1.7 void 类型
void 表示空的, 该类型主要用在函数返回值上
function fn():void{
console.log("没有返回值");
// return 123; // 错误
}
// void类型变量只能赋值undefined或null(在strictNullChecks关闭时)
let unusable: void = undefined;
5.1.8 never 类型
表示永不存在的值的类型,常用于:
- 总是会抛出异常的函数
- 无法正常结束的函数(如死循环)
// 抛出错误的函数
function error(message: string): never {
throw new Error(message);
}
// 无限循环的函数
function infiniteLoop(): never {
while (true) {}
}
5.1.9 对象类型
object 限制类型为对象,但使用更具体的类型更有帮助
// 基本object类型
let o: object = {};
o = [];
o = new Date();
// o = 123; // 错误
// 对象字面量类型
let person: { name: string; age: number } = {
name: "张三",
age: 30
};
// 可选属性
let user: { id: number; email?: string } = {
id: 1
};
5.1.10 数组类型
TypeScript 像 JavaScript 一样可以操作数组元素。数组类型有两种表示方式:
// 方式1: 类型[]
let list1: number[] = [1, 2, 3];
// 方式2: Array<类型>
let list2: Array<string> = ['a', 'b', 'c'];
// 多类型数组
let list3: (number | string)[] = [1, 'a', 2, 'b'];
// 只读数组
let readonlyArr: ReadonlyArray<number> = [1, 2, 3];
// readonlyArr[0] = 5; // 错误:只读数组不能修改
5.1.11 元组类型
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
// 声明一个元组类型
let tuple: [string, number];
// 赋值必须按照类型顺序
tuple = ['hello', 10]; // 正确
// tuple = [10, 'hello']; // 错误:类型不匹配
// 访问元素
console.log(tuple[0].substring(1)); // 'ello'
// console.log(tuple[1].substring(1)); // 错误:number类型没有substring方法
// 可选元素
let tupleWithOptional: [string, number?] = ['hello'];
5.1.12 枚举类型
enum
类型是对JavaScript标准数据类型的一个补充,使用枚举可以定义一些有名字的数值常量。
// 数字枚举:默认从0开始
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right // 3
}
// 可以手动设置枚举值
enum StatusCode {
OK = 200,
NotFound = 404,
Error = 500
}
// 字符串枚举
enum HttpMethod {
GET = "GET",
POST = "POST",
PUT = "PUT",
DELETE = "DELETE"
}
// 使用枚举
let dir: Direction = Direction.Up;
console.log(dir); // 0
console.log(Direction[0]); // "Up"
5.2 类型断言与联合类型
5.2.1 类型断言
类型断言可以用来明确告诉编译器变量的类型,有两种语法形式:
// 语法1: <类型>变量
let someValue: unknown = "this is a string";
let strLength: number = (<string>someValue).length;
// 语法2: 变量 as 类型 (推荐,在JSX中只能使用这种)
let someValue2: unknown = "this is a string";
let strLength2: number = (someValue2 as string).length;
// 类型断言不是类型转换
let n = 123;
// let s = n as string; // 错误:number不能断言为string
// 可以先断言为unknown,再断言为目标类型
let s = (n as unknown) as string;
5.2.2 联合类型
联合类型表示一个值可以是几种类型之一:
// 联合类型
let num: number | string;
num = 123;
num = "abc";
// num = true; // 错误
// 使用类型守卫来处理联合类型
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return " ".repeat(padding) + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error("Expected string or number");
}
5.3 接口与类型别名
5.3.1 接口
接口是 TypeScript 的一个核心概念,用于定义对象的类型:
// 基本接口定义
interface Person {
name: string;
age: number;
}
// 使用接口
let user: Person = {
name: "小明",
age: 20
};
// 可选属性
interface Config {
color?: string;
width?: number;
}
// 只读属性
interface Point {
readonly x: number;
readonly y: number;
}
// 函数类型接口
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc = function(src, sub) {
return src.search(sub) > -1;
};
// 索引类型
interface StringArray {
[index: number]: string;
}
let myArray: StringArray = ["Bob", "Fred"];
5.3.2 类型别名
类型别名用来给一个类型起个新名字:
// 基本类型别名
type Name = string;
type Age = number;
type User = { name: Name; age: Age };
// 联合类型别名
type WindowStates = "open" | "closed" | "minimized";
type StringOrNumber = string | number;
// 函数类型别名
type GreetFunction = (name: string) => string;
// 接口vs类型别名
// 接口可以被继承和实现,类型别名不能
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
// 类型别名可以用于原始类型、联合类型、元组等
type Coordinate = [number, number];
type Callback = (...args: any[]) => void;
5.4 函数
5.4.1 函数类型
TypeScript 可以为函数的参数和返回值指定类型:
// 函数声明
function add(x: number, y: number): number {
return x + y;
}
// 函数表达式
let myAdd: (x: number, y: number) => number =
function(x: number, y: number): number { return x + y; };
// 可选参数
function buildName(firstName: string, lastName?: string): string {
if (lastName) return firstName + " " + lastName;
return firstName;
}
// 默认参数
function greeting(name: string = "World"): string {
return `Hello, ${name}!`;
}
// 剩余参数
function sum(...numbers: number[]): number {
return numbers.reduce((total, n) => total + n, 0);
}