TypeScript学习笔记 | 青训营

88 阅读6分钟

TypeScript学习笔记 | 青训营


这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天


TypeScript发展历程:

TypeScript一开始由微软在2012年发布,在14年Angular发布了基于TypeScript的2.0版本。在16年的时候,React适配了TypeScript。在20年,Vue适配了TypeScript,发布了现在大多数人熟知的Vue3.0。在21年,TypeScript v4.5发布。


那么,什么是TypeScript呢?为什么Angular,React,Vue最后都适配了TypeScript?

TypeScript与JavaScript的区别与联系

JavaScript简称JS,是一种动态类型、弱类型的语言
TypeScript简称TS,是一种静态类型、弱类型的语言,是JavaScript的超集。

那么什么是动态类型? 什么是静态类型?
动态类型语言是指只有在编译后才能发现错误的语言。
静态类型语言是指在未编译(或者说是在构建代码阶段)就能够及时的发现错误的语言。

什么是弱类型语言?
既然有弱类型语言,那么应该也有强类型语言。
C++,C,JAVA这些语言其实都是强类型语言。
比如说,JS中可以使用"" + 数字将数字转化为字符串。 但是C++,JAVA是做不到的。它们必须严格定义自己的变量类型,使用一些如toString类的方法进行转化。

静态类型的特点

  • 可读性增强

它能够基于语法解析TSDoc,ide增强。自动生成文档。便于耗费大量的时间去编写文档,使得项目开发周期延长。

  • 可维护性增强

在编译阶段暴露大部分错误,减少后期维护的时间。在多人协同合作的大型项目中,能够获得更快的开发效率,更好的稳定性。

JS每年都在增加新的内容,TS能够以渐进式的方式引入JS,其包含JS的所有特性。

编辑器推荐

TS由微软官方发布,并在15发布了Visual Studio Code。作为微软自家的编辑器,使用自家编译器写自家发布的语言或许是一个不错的选择。

TypeScript基本语法

基本类型:

与JS不同的是,TypeScript在定义变量时需要指定变量类型。
形如:

// 字符串
const str: string = 'hello juejin';
// 数字
const num: number = 1;
// 布尔值
const bl: boolean = true;
// 空值 null
const nl: null = null;
// 缺省
const udf: undefined = undefined;

console.log(str);
console.log(num);
console.log(bl);
console.log(nl);
console.log(udf);

运行结果为: image.png

基本形式是:const + 变量名 + : + 变量类型 + = + 变量值

对象类型

在TS中,对象类型用interface定义。同时,也可以给对象中的属性设置是否已读,也能够设置可选属性和任意属性。

形如:

interface IObject {
  readonly jobId: number; // 只读属性
  name: string;
  sex: 'man' | 'women' | 'hide'; // 值为三选一
  age: number;
  phone?: string; // 可选属性
  [key: string]: any; // 任意属性
}

const iObject: IObject = {
  jobId: 12345,
  name: 'hihihi',
  sex: 'man',
  age: 21,
  phone: 'xxxxxxxxxxxxx',
}

需要注意的是,基于对象类型创建一个新的对象时,除了缺省值以外,所有属性都必填。另外,可读属性不能被重新赋值。
以下是基于如上代码进行debug调试:

iObject.jobId = 00001
iObject.country = 'China'
const iObject1: IObject = {
  jobId: 123454,
  sex: 'hide',
  age: 20,
}

image.png

image.png

函数类型

在TS中,函数类型与JS不同,需要给每个形参设置变量类型,同时,也需要给返回值设置一个变量类型。
如:

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

const mul: (x: number, y: number) => number = (x, y) => x * y;

console.log(add(3, 5))
console.log(mul(3, 5))

image.png 观察到,形参的基本形式是变量名 + : + 类型
返回值的表达形式其实也可以抽象为:方法 + : 类型 {}。也就是function 函数名(形参)可以抽象为"变量名"。那么形参和返回值正好与定义变量时的表达一致。
即:变量名 + : + 类型

也可以使用const的方法来定义函数。此时需要用到箭头函数。这种方法有时候写的代码会很长不利于阅读,那么就可以使用下面的方法。

interface Imul {
  (x: number, y: number): number;
}
const mult: Imul = (x, y) => x * y;
console.log(mult(3, 5))

看起来像是将(x: number, y: number) => number用Imul折叠起来了。

函数重载

函数重载是使用相同名称和不同参数数量或不同类型创建多个方法的一种能力。
形如:

function add(x: number, y: number): number;
function add(x: number, y: string): string;
function add(x: string, y: number): string;
function add(x: string, y: string): string;
function add(x: string | number, y: string | number): string | number{
  if (typeof x === 'string' || typeof y === 'string') {
    return x.toString() + y.toString();
  }
  else return x + y;
}
console.log(add(3, 5))
console.log(add(3, "5"))
console.log(add("hello", 5))

image.png 观察到,这里为add函数提供了多个函数定义以实现函数的重载,最后一个add使用一个if-else语句实现重载函数的方法。使得所有重载都能够适用。

数组类型

下面是TS的数组类型
形如:

// 数组, 类型 + []
type IArr1 = number[];
// 泛型
type IArr2 = Array<string | number | Record<string, number>>;
// 元组
type IArr3 = [number, number, string, string];
// 接口
interface IArr4 {
  [key: number]: any;
}

const arr1: IArr1 = [1, 2, 3, 4, 5];
const arr2: IArr2 = [1, 2, 3, '45', { jue: 1 }];
const arr3: IArr3 = [1, 2, '34', 'jue jin'];
const arr4: IArr4 = ['string', () => null, {}, []];
console.log(arr1);
console.log(arr2);
console.log(arr3);
console.log(arr4);

image.png 一般来说,泛型和数组是比较常用的,在上面的代码中,泛型是可以通过|使得多种类型用于同一个数组中。

TypeScript的补充类型

  • 空类型
type IEmtFun = () => void;
  • 任意类型
type IAnyType = any;
const num1: IAnyType = 1;
const str1: IAnyType = "hhhh"
console.log(num1)
console.log(str1)

image.png

  • 枚举类型
enum Ecolor { red, orange, yellow, green, cyan, blue, purple };
console.log(Ecolor['red']);
console.log(Ecolor[0]);

image.png 从0开始编号,直到末尾。支持正反映射的特性。

泛型

泛型是允许同一个函数接受不同类型参数的一种方法。
泛型定义数组的方法

type Ixxx = <T>(target: T) => T[];

可以理解为<T>是一个变量,变量的类型是未知的,在函数的执行过程中能够确定。target的类型也是T。最后返回一个T类型的数组。 不预先指定,在使用中自动指定

  • 泛型接口
interface Ixxxx<T, U>{
  key: T;
  val: U;
}
  • 泛型类
class Ixxxxx<T>{
  instance: T;
}
  • 泛型别名
type Ixxxxxx<T> = Array<T>;

在这些类中,<T>都是代表未知的类型。

泛型约束

可以通过使用extends + 类型名约束泛型的类型。 比如:

type Ixxxxxxx = <T extends string>(target: T) => T[];
const getStrArr: Ixxxxxxx = target => new Array(100).fill(target);
getStrArr(123)

image.png 将泛型约束为字符串,那么就不能用number类型赋值。

泛型参数默认类型

可以通过使用=给泛型参数赋予一个默认类型。

type IxxArr<T = number> = (target: T) => T[];
const getRepeatArr: IxxArr = target => new Array(100).fill(target);
getRepeatArr('123')

image.png

类型别名和类型断言

  • 类型别名

当一个类型特别复杂的时候,可以使用类型别名代替他进行表达。 如:

type IObjArr = Array<{
  key: string;
  [Objkey: string]: any;
}>

  • 类型断言

当能够肯定一个类型的值的时候,可以使用as关键字断言该类型为正确类型。

字符串/数字 字面量

TS允许指定字符串或者数字的固定值 形如:

type Ixx = 'a' | 'b' | 'c';
type Ixxx = 1 | 2 | 3 | 6 | 9;

总结

本文简单的罗列了TS的简单语法特性,并对泛型的使用做了一定的说明。但是,泛型的用法不止于此,由于篇幅和时间关系,后面的内容就不再记录。

引用参考: TypeScript 的发展与基本语法 - 掘金 (juejin.cn)