TypeScript规范地系统地学习

758 阅读9分钟

TypeScript规范地系统地学习

笔者是萌新一枚,这次学习总结也是我在学习TypeScript后的第一次总结,我认为总结是学习的结晶。以后我将时常在掘金等网站发布自己的一些学习总结包含一些个人的学习见解。

1.前言

TypeScript是JavaScript的超集,TypeScript是在JavaScript的基础上制定了顶层,该层是TypeScript类型系统。

先说一说JavaScript,JavaScript已经有了一套自己的语言基础,如string, number, object, undefined 等等。但由于是动态语言,没有编译时,便不能在写代码完成后,进行编译,从而完成类型检查,语法检查。

接着说TypeScript,TypeScript扮演上面所说的角色。所以,在总结了一番后,我们知道,TypeScript是包含着JavaSctip的运行时,还扩张了JavaScript所没有的编译时的JavaScript超集。

因此,可以扩展的知道,TypeScript可以使用任何JavaScript的代码。

2.TypeScript类型系统

类型系统-基础类型

类型注解

TypeScript需要在编译时完成类型检查。通常会使用类型注解来帮助完成类型检查,而类型注解一般如下

let title: string = '自主学习';
let n: number = 100;
let isOk: boolean = true;

基础类型的类型注解

TypeScript需要在编译时完成类型检查。所以许多变量在声明的时候,都需要变成TypeScript语法格式的声明,而不再是JavaScript不严谨的声明了。

类型注解的语法是let 变量:类型;

例子:

let helloWorld = "Hello World"; 			// 这样子是JavaScript声明的模板
//let helloWorld: string = "Hello World";   // 这样子是TypeScript声明使用的类型注解模板

// 基元(普通值,基础数据),string,number,boolean等类型的数据
let title: string = '自主学习';
let n: number = 100;
let isOk: boolean = true;

类型推导

如果没有使用类型注解的话,可在声明时,初始化变量,使之默认绑定类型,从而可以不用类型注解。函数参数与返回值也是如此。

例子

let helloWorld = "Hello World"; 			// helloWorld自动绑定为string变量.
// function fn(x: number, y: number): number
function fn(x=1, y=1) {
    return x + y;
}
console.log(fn(1,1))
console.log(fn('1',1))//类型“"1"”的参数不能赋给类型“number | undefined”的参数。ts(2345)

类型系统-数组元组枚举

数组的类型注解

数组类型注解的语法为 let 变量: 类型[];即定义为一种既定类型的数组,不能向数组添加其他类型的元素。

还有一种语法是使用泛型的格式,即 let 变量:Array<类型>;

例子

let arr1: string[] = [];
arr1.push('开课吧'); // 正确
// arr1.push(1); // 错误
// 类型“1”的参数不能赋给类型“string”的参数。ts(2345)

let arr2: Array<number> = [];
arr2.push(100); // 正确
arr2.push('100'); // 错误
// arr2.push('开课吧'); // 错误                 
// 类型“"开课吧"”的参数不能赋给类型“number”的参数。ts(2345)

元组的类型注解

元组类似数组,但是存储的元素类型不必相同。

但是需要遵循两点。

1.必须先初始化,且初始化的值的类型与顺序,与元组的变量类型与顺序,必须一致。

2.初始化完元组后,可越界继续添加,但添加的元素必须是元组内的定义的几个类型。

注意:未开启 strictNullChecks: true 会使用 undefined 进行初始化

元组类型的注解语法是let 变量: [类型一, 类型二,...]

例子

let data1: [string, number] = ['开课吧', 100];
data1.push(100); // 正确
data1.push('100'); // 正确
data1.push(true); // 错误

let data2: [string, number] = ['开课吧', 100];
data2.push(10);

枚举的类型注解

TypeScript的枚举类型是通过enum关键字实现的。

枚举的类型注解语法如下enum 枚举名称 { key1=value, key2=value2 }

注意:

1.注解语法中是使用逗号(,)来分割key=value的。

2.上一个为初始化数字,则如果下一个枚举变量不设定值,则枚举变量是在上一个变量的基础上+1

3.枚举的变量如果不指定值的话,则默认是0,1,2,3...

4.key是不允许是数字开头的命名。

5.value 可以是数字,称为 数字类型枚举,也可以是字符串,称为 字符串类型枚举,但不能是其它值,默认为数字:0

其中第5点最容易忘记,所以切记只有两种类型枚举。

例子:

enum HTTP_CODE {
    OK = 200,// 数字类型枚举
    NOT_FOUND = 404// 数字类型枚举
};
// HTTP_CODE.OK;//200

enum URLS {
    USER_REGISTER = '/user/register',//字符串类型枚举
    USER_LOGIN = '/user/login'		 //字符串类型枚举
}
enum SEQ {
    SEQ = 200,// 数字类型枚举
    SEQ1 	// 201
};

类型系统-其他类型

viod类型

通常使用于函数,如果函数返回值是undefined或者(但执行到return时)没有返回值,则可将类型注解声明成 : void

类型注解语法时 变量: void。即表示没有任何数据的类型。

例子:

// 无值类型
function fn(): void {
    
}
fn();
let fnfn :void = undefined;

never类型

通常使用于函数,执行函数的时候,执行不到return时,则函数返回类型就是never.

注解语法是: 变量: never

注意:never是其他类型的子类型。(但是反过来不行)

例子:

let fnfn :void = undefined;
function fn(): never {
    throw new Error('Error');
}
let a: string;
a = fn();		//never类型可以赋值给string变量。
fnfn = fn();	//never类型可以赋值给void类型变量。
let b : any;
b = fn();		//never类型可以赋值给any类型变量。
// 反过来赋值不行
// let b: never;
// let c: any = 1;
// b = c;

any类型

如果类型实在不确定,则可以明确声明变量是any类型.

类型注解的语法是变量:any

注意:

1.任何值都可以赋值给 any 类型

2.any类型也可以赋值给任意类型

3.any类型有任意属性和方法

4.标注为 any 类型,也意味着放弃对该值的类型检测,同时放弃 IDE 的智能提示

(小技巧:指定 noImplicitAny 配置为 true,当***函数参数***出现隐含的 any 类型时报错)

例子:

let an: any;

// 任何值都可以赋值给 any 类型
an = 1;
an = '1'

// any类型也可以赋值给任意类型
let b: string;
b = an;
let flag: boolean;
flag  = an;

// any类型有任意属性和方法
an.indexOf();

// 指定 noImplicitAny 配置为 true
// 当函数参数出现隐含的 any 类型时报错
function fn(an) { //出现提示如下
    // 参数“an”隐式具有“any”类型。ts(7006)
    an.inde();
}

let a: any;
//没有VS Code 等编辑器的智能提示
a.indexOf(); 

unknown类型

如果类型实在不确定,但是知道变量没有方法和变量,则可以明确声明变量是unknown类型.

类型注解的语法是变量:unknown

注意:

1.与any类型相同的是,任意类型都可以赋值给 unknown类型

2.与any类型不同的是,

unknown类型不能赋值给任意类型,只能赋值给any类型或unknown类型

unknown类型没有有任意属性和方法

let a: unknown;
let b: unknown;
let an : any;
// 只能赋值给`any`类型或`unknown`类型
a = an;
b = a;

// 任意类型都可以赋值给 unknown 类型
let str :string = "str";
let obj :Object = {}
a = str;
a = obj;

// unknown 类型没有有任意属性和方法
a.indexOf();// 出现提示如下
// 对象的类型为 "unknown"。ts(2571)

函数类型

类型注解语法function 函数名称(参数1: 类型1,参数2:类型2...):返回值类型{}

let add = function(x: number, y: number): number {
    return x + y;
}

function foreach(data: string[], callback:(k: number, v: string) => void) {
    for (let i:number = 0; i<data.length; i++) {
        callback(i, data[i]);
    }
}

let arr = ['a', 'b', 'c'];
let obj = {}
foreach(arr,function(k,v){})

接口类型定义

注意:接口是一种类型,不能作为值去使用

JavaScript是动态语言,允许使用多种设计模式。但在使用动态编程后,特定情况下,存在一些设计模式很难自动提供类型。

这些类型如果静态化后,那提供静态编程的,并支持JavaScript语言的TypeScript就允许使用这些设计模式了。因为类型确定下来了,TypeScript提供了告知类型的位置。

接口一般声明

一种描述此接口类型的显式方法是通过interface声明:

interface User {
  name: string;
  id: number;
}

接下来就可以使用了

const user: User = {
  name: "Hayes",
  id: 0,
};

注意:

声明User类型的user变量,必须严格按照User对象类型使用。

不然编译时,TypeScript会显示提出错误。

兼容class使用接口类型定义

因为JavaScript支持class和面向对象的编程,所以TypeScript也是如此-接口声明也可以与类一起使用:

interface User {
  name: string;
  id: number;
}

class UserAccount {
  name: string;
  id: number;

  constructor(name: string, id: number) {
    this.name = name;
    this.id = id;
  }
}

const user: User = new UserAccount("Murphy", 1);

可选属性,只读属性,任意属性

可选属性,只读属性,任意属性在接口类型中使用。

可选属性 的语法是 属性名?: 属性类型

只读属性 的语法是readonly 属性名: 属性类型

任意属性 的语法是[prop:索引类型] :属性类型

我们希望给一个接口添加任意属性,可以通过索引类型来实现

注意 :

1.索引类型一般是字符串或者数字。

定义为字符串时候,可以使用数字。如p4[1] = 1;

定义为数字的时候,不可以使用字符串。如p4[‘1’] = 1;//编译报错

2.同时使用两个任意属性的话,

如prop1:string number和[prop2:number]:number则可以,因为属性类型相同。

但是第二个定义成[prop2:number]:Date则将报错。因为属性类型不同。

属性类型需要满足索引类型为数字的必须满足所以类型为字符串的子类型。

//可选属性 只读属性
interface Point3 {
    x: number;
    readonly y: number;
    color?: string;
}

let p3: Point3 = {
    x: 1,
    y: 1,
};
p3.x;
p3.x = 10;
p3.y
// p3.color = 'green';

//任意属性
interface Point4 {
    x: number;
    y: number;
    [prop: string]: number;
}

let p4: Point4 = {
    x: 1,
    y: 1,
    z: 1
}
p4.t = 10;
p4[1] = 1;

下面内容将下次整理:

类型深入-联合类型-交叉类型-字面量类型-类型别名-类型推导-类型断言

类型深入-类型操作符

类型深入-类型保护

文章引用了TypeScript官网的一些知识。并且引入了在开课吧TypeScript最新免费学习课的知识点的学习成果。