TypeScript入门 | 青训营笔记
这是我参与「第四届青训营 」笔记创作活动的第5天
一、TypeScript发展历史
2012-10:微软发布TypeScript第一个版本(0.8) 2020-09:Vue发布了3.0版本,官方支持TypeScript
二、为什么选择使用TypeScript
JS
- 动态类型-->执行阶段做类型匹配
- 弱类型语言-->执行过程中进行类型转换
TS
- 静态类型-->提前进行匹配(编译)-->增强可读性、可维护性
- 弱类型语言
三、基本语法
1、基础数据类型
关键字定义类型
2、对象类型
在面向对象语言中,接口是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类去实现
interface定义IBytedancer接口
3、函数
为函数加入类型声明
4、函数重载
5、数组类型
- 【类型 + 方括号】表示
- 泛型
- 接口表示
- 元组表示
- 【类型 + 方括号】表示
type IArr1 = number[];
const arr1:IArr1 = [1,2,3,4,5,6];
- 泛型
type IArr2 = Array<string| number| Record<string, number>>;
const arr2:IArr2 = [1,2,'3','4',{a:1}];
- 接口
interface IArr3{
[key:number]:any;
}
const arr3:IArr3 = ['string', () => numll, {}, []];
- 元组
type IArr4 = [number, number, string, string];
const arr4:IArr4 = [1,2,'3','4'];
6、泛型
泛型就是在定义函数,接口或者类的时候没有指定具体类型,等到使用时才指定具体类型,极大程度的复用代码
泛型类:泛型类看上去与泛型接口差不多,泛型类使用(`<>`)括起泛型类型,跟在类名后面
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
泛型约束:在`loggingIdentity`例子中,我们想访问`arg`的`length`属性,但是编译器并不能证明每种类型都有`length`属性,所以就报错了
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}
我们想要限制函数去处理任意带有.length属性的所有类型。 只要传入的类型有这个属性,我们就允许,就是说至少包含这一属性。 为此,我们需要列出对于T的约束要求
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
loggingIdentity({length: 10, value: 3});
四、高级类型
1、联合/交叉类型
联合类型:联合类型表示一个值可以是几种类型之一。 我们用竖线(`|`)分隔每个类型,所以`number | string | boolean`表示一个值可以是`number`,`string`,或`boolean`
交叉类型: IA & IB; 多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性
const bookList =[{
author:'xiaoming',
type:'history',
range:'2001-2021',
},{
author:'xiaoli',
type:'story',
theme:'love',
}]
type IBookList = Array<{
author:string;
}&({
type:'history';
range:string;
}|{
type:'story';
theme:string;
})>
2、类型保护与类型守卫
类型保护就是一些表达式,它们会在运行时检查以确保在某个作用域里的类型。 要定义一个类型保护,我们只要简单地定义一个函数,它的返回值是一个类型断言
类型断言
let pet = getSmallPet();
if ((<Fish>pet).swim) {
(<Fish>pet).swim();
}
else {
(<Bird>pet).fly();
}
typeof类型保护
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
instanceof类型保护
instanceof类型保护*是通过其构造函数来细化其类型
interface Padder {
getPaddingString(): string
}
class SpaceRepeatingPadder implements Padder {
constructor(private numSpaces: number) { }
getPaddingString() {
return Array(this.numSpaces + 1).join(" ");
}
}
class StringPadder implements Padder {
constructor(private value: string) { }
getPaddingString() {
return this.value;
}
}
function getRandomPadder() {
return Math.random() < 0.5 ?
new SpaceRepeatingPadder(4) :
new StringPadder(" ");
}
// 类型为SpaceRepeatingPadder | StringPadder
let padder: Padder = getRandomPadder();
if (padder instanceof SpaceRepeatingPadder) {
padder; // 类型细化为'SpaceRepeatingPadder'
}
if (padder instanceof StringPadder) {
padder; // 类型细化为'StringPadder'
}
instanceof的右侧要求为一个构造函数,TypeScript将细化为:
- 这个函数的
prototype属性,如果它的类型不为any的话 - 类型中构造签名所返回的类型的联合,顺序保持一致