1.1. 简单介绍
1.1.1 TypeScript VS JavaScript
两者的区别(重点!):
| TypeScript | JavaScript |
|---|---|
| JavaScript的超集,用于解决大型项目的代码复杂性 | 一种脚本语言,用于创建动态网页 |
| 强类型,支持静态和动态类型 | 动态弱类型语言 |
| 可以在编译期间发现并修正错误 | 只能在运行时发现错误 |
| 不允许改变变量的数据类型 | 变量可以被赋值成不同类型 |
ts是js的扩展,ts能转化为js运行。
1.1.2 学习推荐
- TS开源教程以及应用:github.com/dzharii/awe…
- TS到JS在线编译:www.typescriptlang.org/play?#code/…
1.2. TS基础
1.2.1. 基本类型
- boolean、number、string
- 枚举enum
- any(任意类型)、unknow、void
- never
- 数据类型[]
- 元组类型tuple(特殊的数组,需要显示的标注出元素的类型)
1.2.2. TS基础-函数类型
- 定义:TS定义函数类型时要定义输入参数类型和输出类型
- 输入参数:参数支持可选参数(?表示)和默认参数(=表示)
- 输出参数:输出可以自动推断,没有返回值时,默认为void类型
- 函数重载:名称相同但参数不同,可以通过重载支持多种类型 例如:
function add(x: number, y: number): number {
return x + y;
}
接受两个 number 类型参数 x 和 y,并返回一个 number 类型的值。
5. 可以使用 type 关键字或 interface 关键字来定义函数类型别名,例如
type Greeting = (name: string, age?: number) => void;
const greet: Greeting = (name, age = 30) => {
console.log(`Hello, \${name}! You are \${age} years old.`);
};
在这个例子中,我们定义了一个 Greeting 类型的函数,它接受一个必传的 name 参数和一个可选的(问好表示) age 参数。age 参数使用了默认值,如果调用函数时未提供 age 参数,则默认为 30。
1.2.3. interface(接口)
- 定义:接口是为了定义对象类型
- 特点:可选属性(?) 只读属性(readonly) 可以描述函数类型 可以描述自定义属性
- 总结:接口非常灵活duck typing
interface 关键字用于定义接口,它主要用于描述对象的形状(属性和方法),例如:
interface Car {
brand: string;
model: string;
}
const car : Car = {
brand: 'aodi';
model: 'daxing';
}
1.2.4. 类
- 定义:写法和JS差不多,增加了一些定义
- 特点:增加了
public(公有的,这个是默认值)、private(私有的,继承类和实例都不能调用private定义的私有属性,只能在原型上用)、protected(受保护的,仅支持在继承类和原型里被调用)修饰符abstract抽象类:只能被继承,不能被实例化;作为基类,抽象方法必须被子类实现- interface约束类,使用implements关键字
1.3 TS进阶
1.3.1. 高级类型
- 联合类型 | 。例如,
string | number表示一个值可以是字符串或者数字。 - 交叉类型 & 。
Type1 & Type2表示一个值同时具有 Type1 和 Type2 的属性和方法。 - 类型断言:用于告诉编译器某个值的具体类型。它允许我们使用我们确定的类型覆盖编译器自己的类型推断。
- 尖括号语法:使用
<Type>的形式进行断言。
let value: any = "Hello World";
let length: number = (<string>value).length; // 断言value是string类型
- as语法:使用
value as Type的形式进行断言。
let value: any = "Hello World";
let length: number = (value as string).length; // 断言value是string类型
注意: 无论使用哪种语法形式,类型断言只影响编译阶段,不会影响运行时的对象类型。当进行类型断言时,我们需要确保类型断言的类型和实际类型是兼容的,否则可能会导致运行时错误。
- 非空断言(Non-null Assertion):用于告诉编译器一个值一定不为 null 或 undefined。使用!来进行非空断言。
let name: string | undefined = getUsername();
let length: number = name!.length; // 告诉编译器name一定有值
- 类型守卫(Type Guard):通过检查运行时的条件来缩小变量的类型范围,不需要显式的类型断言。
interface Cat {
meow(): void;
}
interface Dog {
bark(): void;
}
function makeSound(animal: Cat | Dog) {
if ("meow" in animal) { //使⽤这种 "in" 操作符可以根据运⾏时的条件来缩窄变量的类型范围,
animal.meow();
} else {
animal.bark();
}
}
上述例子中,定义了两个接口 Cat 和 Dog,它们分别表示猫和狗,并且都有一个方法,meow() 和 bark()。
makeSound 是一个函数,它接受一个参数 animal,类型为 Cat 或 Dog 的联合类型。在函数内部,它使用 if ("meow" in animal) 条件语句来检查 animal 是否具有 meow() 方法。如果 animal 接受传来的实参 是 Cat 类型,则执行 animal.meow() 方法;如果 animal 是 Dog 类型,则执行 animal.bark() 方法。
注意: 过度使用类型断言可能会导致类型不安全。应该在确保类型一致性的情况下谨慎使用类型断言。
- 类型别名(type VS interface ):
-
定义:给类型起个别名
-
相同点:
- 都可以定义对象或函数
- 都允许继承
-
差异点:
- interface是TS用来定义对象的,type是用来定义别名方面使用
- type可以定义基本类型,interface不行
- interface可以合重复声明,type不行
- 字面量类型(Literal Types):字面量类型允许我们指定一个具体的值作为类型。例如,type Color = "red" | "green" | "blue" 定义了一个名为 Color 的新类型,它只能取 "red"、"green" 或 "blue" 这三个值中的一个。
1.3.2 泛型
什么时候需要泛型
软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性
组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能
可以参考C++中的模板函数来理解。
泛型的定义
允许我们在定义函数、类或接口时使用参数化类型。
基本使用
- 泛型的语法是<>里面写类型参数,一般用T表示
- 使用时有两种方法指定类型:
- 定义要使用的类型
- 通过TS类型推断,自动推导类型
- 泛型的作用是临时占位,之后通过传来的类型进行推导 例如:
// 泛型函数
function identity<T>(arg: T): T {
return arg;
}
let result = identity<number>(10);
console.log(result); // 输出:10
基础操作符
- typeof:获取类型
- keyof:获取所有键,也就是一个类型的所有属性名构成的联合类型。
- in:遍历枚举类型
- T[K]:索引访问
- extends:泛型约束。 我们可以限制泛型参数只能是特定类型或者实现了特定接口的类型。这样可以确保传入的参数满足一定的条件。
function printName<T extends { name: string }>(obj: T) {
console.log(obj.name);
}
printName({ name: "Alice", age: 25 }); // 输出:Alice
在上述示例中,泛型约束 T extends { name: string } 表示泛型参数 T 必须满足一个对象类型的约束,即对象类型必须包含 name 属性,并且它的类型是 string。这样,在 printName 函数中就可以安全地访问 obj.name 属性。
常用工具类型
- Partial:将类型属性变为可选
- Required:将类型属性变为必选
- Readonly:将类型属性变为只读
- Pick<T, K> 、Record<T, K> ...
- Pick<T, K> 是一个从泛型类型 T 中选取部分属性的工具类型。它接受两个参数:T 表示源类型,K 表示要选取的属性名的联合类型。
- Record<K, T> 是一个创建具有指定键类型 K 和值类型 T 的对象的工具类型。它接受两个参数:K 表示键的类型,T 表示值的类型。
type Fruit = 'apple' | 'banana' | 'orange';
type FruitInventory = Record<Fruit, number>;
const inventory: FruitInventory = {
apple: 5,
banana: 3,
orange: 7
};
在上述示例中,Record<Fruit, number> 创建了一个类型 FruitInventory,它是以 Fruit 类型中的每个值为键,以 number 类型为值的对象类型。所以 inventory 变量是一个具有 apple、banana 和 orange 三个键的对象,对应的值都是 number 类型。
1.4 TS实战
1.4.1 声明文件
-
declare:三方库需要类型声明文件
-
.d.ts:声明文件定义
-
@types:三方库TS类型包
-
tsconfig.json:定义了TS的配置