TypeScript入门 | 青训营笔记

49 阅读3分钟

TypeScript入门 | 青训营笔记

这是我参与「第四届青训营 」笔记创作活动的第5天

一、TypeScript发展历史

2012-10:微软发布TypeScript第一个版本(0.8) 2020-09:Vue发布了3.0版本,官方支持TypeScript

二、为什么选择使用TypeScript

JS

  • 动态类型-->执行阶段做类型匹配
  • 弱类型语言-->执行过程中进行类型转换

TS

  • 静态类型-->提前进行匹配(编译)-->增强可读性、可维护性
  • 弱类型语言

三、基本语法

1、基础数据类型

关键字定义类型

1.png

2、对象类型

在面向对象语言中,接口是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类去实现

interface定义IBytedancer接口

2.png

3、函数

为函数加入类型声明

3.png

4、函数重载

4.png

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将细化为:

  1. 这个函数的prototype属性,如果它的类型不为any的话
  2. 类型中构造签名所返回的类型的联合,顺序保持一致