TypeScript是什么
# TypeScript 是什么

# 体验 typescript
因为 node.js 和浏览器只认 js,不认识 ts 代码。需要先将 TS 代码转化为 JS 代码,然后才能运行
- 全局安装 typescript
npm i -g typescript
- 验证是否安装成功
tsc –v # 成功安装后会显示Typescript版本如Version 5.8.3
编译并运行 typescript
使用 tsc 命令编译 ts 文件
tsc index.ts
1自动化编译
- 创建 TypeScript 编译控制⽂件
tsc --init
1- 监视⽬录中的 .ts ⽂件变化
tsc --watch 或 tsc -w
1- 当编译出错时不⽣成 .js ⽂件
tsc --noEmitOnError --wat
1
# 基础类型
# JavaScript 原有基础类型
类型 | 描述 | 示例 |
---|---|---|
boolean | 布尔值 | let isDone: boolean = false |
number | 数字(包括整数和浮点数) | let decimal: number = 6 |
string | 字符串 | let color: string = "blue" |
null | 空值 | let n: null = null |
undefined | 未定义 | let u: undefined = undefined |
symbol | ES6 新增的唯一标识符类型 | let sym: symbol = Symbol() |
bigint | 大整数(ES2020 新增) | let big: bigint = 100n |
# TypeScript 新增基础类型
类型 | 描述 | 示例 |
---|---|---|
any | 任意类型(不推荐常规使用) | let notSure: any = 4 |
unknown | 类型安全的 any | let unsure: unknown = 4 |
void | 无返回值(常用于函数) | function warn(): void { console.log('warning') } |
never | 永不存在的值(异常或无限循环) | function error(): never { throw new Error() } |
object | 非原始类型 | let obj: object = {} |
# 数组和元组类型
类型 | 描述 | 示例 |
---|---|---|
类型[] | 数组 | let list: number[] = [1, 2, 3] |
Array<类型> | 数组泛型写法 | let list: Array<number> = [1, 2, 3] |
[类型, 类型] | 元组(固定长度和类型的数组) | let tuple: [string, number] = ['he', 10] |
# 枚举类型
枚举可以清晰地表达意图或创建一组有区别的用例。 TypeScript 支持数字的和基于字符串的枚举
- 使用
enum
关键字定义枚举。 - 约定枚举名称、枚举中的值以大写字母开头。
- 枚举中的多个值之间通过 ,分隔。
数组枚举
enum Direction {
Up = 1,
Down,
Left,
Right,
}
2
3
4
5
6
字符串枚举
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
2
3
4
5
6
异构枚举
enum BooleanLikeHeterogeneousEnum {
No = 0,
Yes = "YES",
}
2
3
4
# 字面量类型
字面量类型(Literal Types)是 TypeScript 中的一种特殊类型,它允许你将变量的值限定为特定的字面量值,而不是某种宽泛的类型。
字符串字面量类型
type Direction = "north" | "east" | "south" | "west";
function move(direction: Direction) {}
move("north"); // 正确
move("up"); // 错误:'up' 不是 Direction 类型
2
3
4
5
6
数字字面量类型
type Dice = 1 | 2 | 3 | 4 | 5 | 6;
function rollDice(): Dice {
return 3; // 只能返回 1-6 的数字
}
2
3
4
5
# 类型别名
类型别名(Type Aliases)是 TypeScript 中用来给类型起一个新名字的特性,它可以简化复杂类型的定义,提高代码的可读性和可维护性。
基本语法
使用type
关键字创建类型别名
type NewTypeName = ExistingType;
常见用途
1.简化基础类型
type UserID = string;
type Age = number;
let id: UserID = "user123";
let age: Age = 30;
2
3
4
5
2.定义复杂类型
type Point = {
x: number;
y: number;
};
function draw(point: Point) {}
2
3
4
5
6
3.联合类型别名
type Status = "pending" | "success" | "error";
function handleResponse(status: Status) {}
2
3
4.函数类型别名
type ClickHandler = (event: MouseEvent) => void;
const handleClick: ClickHandler = (e) => {
console.log("Clicked at:", e.clientX, e.clientY);
};
2
3
4
5
# 接口
接口(Interface)是 TypeScript 的核心概念之一,它用于定义对象的形状(Shape),即对象应该具有哪些属性和方法
基本语法
interface InterfaceName {
property1: type;
property2: type;
method1(): returnType;
}
2
3
4
5
核心特性
1.定义对象结构
interface Person {
name: string;
age: number;
greet(): void;
}
const alice: Person = {
name: "Alice",
age: 30,
greet() {
console.log(`Hello, I'm ${this.name}`);
},
};
2
3
4
5
6
7
8
9
10
11
12
13
2.可选属性
interface User {
username: string;
email?: string; // 可选属性
}
2
3
4
只读属性
interface Point {
readonly x: number;
readonly y: number;
}
2
3
4
# 类型注解
// 基础类型
// 数组类型(两种写法)
let arr: number[] = [1, 2, 3];
let str: string[] = ["1", "2", "3"];
/**
* 表示这个数组中既有string类型,也有number类型
* | 在 TS 中叫做联合类型(由两个或多个其他类型组成的类型,表示可以是这些类型中的任意一种)
*/
let arr_str: (string | number)[] = [1, 34, 4, "8"];
let arr1: Array<string> = ["1", "3"];
let arr3: Array<number | string> = [1, "3"];
2
3
4
5
6
7
8
9
10
11
12
# 类型断言
类型断言(Type Assertion)是 TypeScript 中告诉编译器"你比它更了解某个值的类型"的一种方式。它类似于其他语言中的类型转换,但不进行特殊的数据检查或解构。
两种写法
// 使用 as 关键字实现类型断言。
let link = document.getElementById("link") as HTMLAnchorElement;
// 使用 <> 语法
let aa = <HTMLAnchorElement>document.getElementById("cen");
2
3
4
提示
可以通过console.dir()
打印 DOM 元素,在属性列表的最后面,即可看到该元素的类型
# any 类型
any
是 TypeScript 中的一个特殊类型,它表示可以是任何类型的值。使用 any 类型会绕过 TypeScript 的类型检查
any 类型特点
绕过类型检查
- 可以赋值为任何类型的值
- 可以访问任何属性
- 可以调用任何方法
let obj: any = { x: 0 }; obj.foo(); // 不会报错(运行时可能出错) obj(); // 不会报错 obj.bar = 100; // 不会报错
1
2
3
4与任何类型兼容
会污染类型系统
# typeof
TypeScript 中的 typeof 操作符有两种主要用法,既保留了 JavaScript 中 typeof 的运行时行为,又增加了类型层面的类型查询功能。
- JavaScript 风格的运行时 typeof(值空间)
let str = "hello";
console.log(typeof str); // 输出: "string"
let num = 123;
console.log(typeof num); // 输出: "number"
let bool = true;
console.log(typeof bool); // 输出: "boolean"
2
3
4
5
6
7
8
- TypeScript 类型查询(类型空间)
let obj = { x: 1, y: 2 };
function formatPoint(point: typeof obj) {}
// 等同于
function formatPoint(point: { x: nunmber; y: nunmber }) {}
formatPoint({ x: 1, y: 89 });
2
3
4
5
6
7
注意
typeof
只能用来查询变量或属性的类型,无法查询其他形式的类型(比如,函数调用的类型)。
# 高级类型
# class 类
类(Class) 是 ES6 (ECMAScript 2015) 引入的一种语法特性,它本质上是一种特殊的函数,提供了一种更清晰、更面向对象的方式来创建对象和处理继承
# 基本类定义
class Person {
// 属性声明(可以带类型注解)
name: string;
age: number;
// 构造函数
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 方法
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
// 使用类
const person = new Person("Alice", 30);
person.greet();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
注意
构造函数不需要返回值类型
# 访问修饰符
class Animal {
public name: string; // 公开访问(默认)
private id: number; // 仅类内部访问
protected age: number; // 类及其子类可访问
readonly species: string; // 只读属性,不能修饰方法
constructor(name: string, age: number) {
this.name = name;
this.age = age;
this.id = Math.random();
this.species = "Animal";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# 类继承
# extends(继承父类)
类继承是面向对象编程的核心概念之一,它允许一个类(子类/派生类)基于另一个类(父类/基类)来创建,继承父类的属性和方法,同时可以添加或修改自己的特性。
继承的关键要素
extends
关键字:建立继承关系super()
调用:必须在子类构造函数中首先调用
class Parent {
constructor(name: string) {
this.name = name;
}
sayHello() {
console.log(`Hello, ${this.name}`);
}
}
class Child extends Parent {
constructor(name: string, age: string) {
super(name); // 调用父类构造函数
this.age = age;
}
sayAge() {
console.log(`I am ${this.age} years old`);
}
}
const child = new Child("Alice", 10);
child.sayHello(); // 继承自Parent的方法
child.sayAge(); // Child自己的方法
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# implements(实现接口)
implements 是 TypeScript 中的一个重要关键字,用于类实现接口的约束机制。它确保类符合特定的结构规范。
interface Vehicle {
start(): void;
stop(): void;
}
class Car implements Vehicle {
start() {
console.log("Car started");
}
stop() {
console.log("Car stopped");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# 两者区别
特性 | implements | extends |
---|---|---|
用途 | 实现接口规范 | 继承类或另一个接口 |
数量 | 可同时实现多个接口 | 只能继承一个类或接口 |
实现方式 | 必须实现所有成员 | 自动继承所有成员 |
运行时影响 | 纯类型检查,无运行时影响 | 会影响原型链和运行时行为 |
# 交叉类型
交叉类型是 TypeScript 中的一种高级类型,它通过
&
运算符将多个类型合并为一个类型,新类型将同时具备所有成员类型的特性
基本语法
type CombinedType = TypeA & TypeB;
核心特性
1. 合并对象类型(最常见用法)
type Person = {
name: string;
age: number;
};
type Employee = {
id: number;
department: string;
};
type Staff = Person & Employee;
const staff: Staff = {
name: "Alice",
age: 30,
id: 123,
department: "IT",
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2. 合并函数类型
type Loggable = {
log: (message: string) => void;
};
type Serializable = {
serialize: () => string;
};
type Logger = Loggable & Serializable;
const logger: Logger = {
log(message) {
console.log(message);
},
serialize() {
return "Serialized data";
},
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 联合类型
联合类型是 TypeScript 的核心特性之一,它允许一个值属于多种类型中的一种,使用竖线
|
符号连接多个类型。
基本语法
type UnionType = Type1 | Type2 | Type3;
核心特性
1. 基础类型联合
type StringOrNumber = string | number;
function printId(id: StringOrNumber) {
console.log(`ID: ${id}`);
}
printId(101); // 合法
printId("ABC"); // 合法
printId(true); // 错误:boolean 不在联合类型中
2
3
4
5
6
7
8
9
2. 对象类型联合
type Circle = {
kind: "circle";
radius: number;
};
type Square = {
kind: "square";
sideLength: number;
};
type Shape = Circle | Square;
function getArea(shape: Shape) {
// 需要类型收窄才能安全访问特定属性
if (shape.kind === "circle") {
return Math.PI * shape.radius ** 2;
}
return shape.sideLength ** 2;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 索引签名类型
索引签名类型是 TypeScript 中一种特殊的类型定义方式,它允许我们定义对象中动态属性名的类型规则。
基本语法
interface MyInterface {
[key: KeyType]: ValueType;
}
2
3
key
可以是任意标识符(通常使用key
或index
)KeyType
只能是string
、number
或symbol
类型ValueType
可以是任意类型
两种主要类型
- 字符串索引签名
interface StringDictionary {
[key: string]: string; // 所有字符串键对应的值都必须是string
}
const dict: StringDictionary = {
name: "Alice",
age: "30", // 注意:虽然键是"age",但值必须是string
// age: 30 // 错误,因为ValueType是string
};
2
3
4
5
6
7
8
9
- 数字索引签名
interface NumberArray {
[index: number]: string; // 数字索引对应string值
}
const arr: NumberArray = ["a", "b", "c"];
const item = arr[0]; // string类型
2
3
4
5
6
# 映射类型
映射类型是 TypeScript 中一种强大的类型操作工具,它允许你基于现有类型创建新的类型,通过系统性地转换属性来实现。
基本语法
type MappedType = {
[Property in keyof OriginalType]: NewType;
};
2
3
Property
是类型变量(可以是任意名称)keyof OriginalType
获取原始类型的所有属性名的联合类型NewType
是基于原始属性类型的转换表达式
# 泛型
泛型是 TypeScript 中创建可重用组件的核心工具,它允许我们定义类型变量,在代码使用时才指定具体类型。
# 基本概念
泛型通过在尖括号< >中声明类型参数来实现:
function identity<T>(arg: T): T {
return arg;
}
2
3
# 核心特性
# 泛型函数
function logAndReturn<T>(value: T): T {
return value;
}
const num = logAndReturn<number>(42); // 显式指定类型
const str = logAndReturn("hello"); // 类型推断
2
3
4
5
6
# 泛型接口
interface KeyValuePair<K, V> {
key: K;
value: V;
}
const pair: KeyValuePair<string, number> = {
key: "age",
value: 30,
};
2
3
4
5
6
7
8
9
# 泛型类
class Box<T> {
private content: T;
constructor(value: T) {
this.content = value;
}
getValue(): T {
return this.content;
}
}
const stringBox = new Box<string>("secret");
const numberBox = new Box(42); // 类型推断
2
3
4
5
6
7
8
9
10
11
12
13
14
# 泛型约束
使用
extends
限制类型参数的范围
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(arg: T): void {
console.log(arg.length);
}
logLength("hello"); // 合法,string有length属性
logLength(42); // 错误,number没有length属性
2
3
4
5
6
7
8
9
10
- 键名约束
<Type>
表示对象的类型<Key extends keyof Type>
表示属性键名,约束为 Type 的键名的联合类型
function getPorp<Type, key extends keyof Type>(obj: Type, key: key): Type[Key] {
return obj[key];
}
getPorp({ name: "100", age: 20 }, "name");
2
3
4
# 泛型工具类型
TypeScript 提供了一系列内置的泛型工具类型(Utility Types),用于对现有类型进行转换和操作。这些工具类型极大地增强了类型系统的灵活性和表达能力。
# Partial<T>
将类型
T
的所有属性变为可选属性
interface User {
id: number;
name: string;
age: number;
}
type PartialUser = Partial<User>;
// 等同于 { id?: number; name?: string; age?: number; }
2
3
4
5
6
7
8
# Readonly<T>
将类型
T
的所有属性变为只读属性
type ReadonlyUser = Readonly<User>;
// 等同于 { readonly id: number; readonly name: string; readonly age: number; }
2
# Required<T>
将类型
T
的所有属性变为必选属性
type RequiredUser = Required<PartialUser>;
// 等同于原始 User 接口
2
# Pick<T, K>
从类型 T 中选取一组属性 K 来构造类型
type UserNameAndAge = Pick<User, "name" | "age">;
// 等同于 { name: string; age: number; }
2
# Record<K, T>
构造一个属性键为 K,属性值为 T 的类型
interface User {
id: number;
name: string;
}
// 使用 Record 定义一个用户映射类型
type UserMap = Record<string, User>;
// 合法的 UserMap 对象
const users: UserMap = {
user1: { id: 1, name: "Alice" },
user2: { id: 2, name: "Bob" },
user3: { id: 3, name: "Charlie" },
};
2
3
4
5
6
7
8
9
10
11
12
13
14
# Omit<T, K>
从类型 T 中排除一组属性 K 来构造类型
type UserWithoutAge = Omit<User, "age" | "name">;
// 等同于 { id: number; }
2