一、简介
TypeScript 简称 TS,是 JavaScript 的超集,也就是在 JavaScript 的基础上,进行扩展,加入了类型注解等新概念。TS与JS之间的关系,类似于Less/Sass 和 CSS之间的关系,我们在文件中写好的TS代码,最终还是会被编译成JS,然后再去执行。JS是弱类型的语言,而TS是强类型的语言。
TS支持各类最新的JS特性,还提供了一套代码的静态检查机制,让问题在编译时就被发现。而重要的是:TS支持像C、Java 等后端语言的某些特性,如枚举、泛型、类型转换、类、接口等。总之,TS的出现,让前端的开发语言变的更完善了。
安装TS: npm i -g typescript
二、类型注解
TS 规定在声明变量时,需要明确变量的数据类型,例如:
let age: number = 18 // 限制age只能存储number类型的数据
let name: string = 'Tom' // 限制name只能存储string类型的数据
...
这种以 变量: 数据类型
的形式,来为变量添加类型约束的方式就是TS的类型注解,你在声明时约定了什么类型,就只能给变量赋什么类型的值,不可发生改变:
let age: number = 18 // 限制age只能存储number类型的数据
age = '二十' // 如果赋其他类型的值 则会报错
如果一个函数有形参和返回值,那么TS要求在声明函数的时候需要将形参和返回值也进行类型注解:
// 函数名(形参1:数据类型,形参2:数据类型): 返回值的数据类型
// x-数值型 y-数值型 返回值-数值型
function sum(x: number, y: number): number {
return x + y;
}
如果某变量可以是多种数据类型,我们可以用联合类型:
let age: (number | string); // age 可以是number 也可以是string
// 或者声明一个type类型
type Combinable = string | number;
let age: Combinable;
联合类型通常都与 null 或undefined一起使用:
const sayHello = (name: string | undefined) => { };
sayHello("semlinker");
sayHello(undefined);
三、数据类型
TS中的数据类型除了JS中的数据类型,还新增了部分数据类型,总共有:any、string、number、boolean、null、undefined、object、bigint、symbol、元组、void等等,常用的数据类型有:any、string、number、boolean。
1、any
在 TS 中 any 类型是顶级类型,任何类型的数据都可以被归类为any,如果我们讲一个变量的类型注解设置为any类型,那么TS允许我们给该变量赋任何类型的值,不受任何约束:
let a: any = 666; // 类型注解为any
a = "Semlinker"; // 赋字符串
a = false; // 赋布尔值
a = 66 // 赋数字
a = undefined // undefined
a = null // null
a = [] // 数组
a = {} // 对象
如果一个变量在声明的时候,没有设置类型注解,那系统会默认将其设置为 any 类型:
let something;
// 等价于
let something: any;
虽然any使用起来很方便,但使用 any 就无法使用 TS提供的大量保护机制,所以我们要尽量减少any的使用,尽量明确变量的类型。
2、null和undefined
在默认情况下,TS中的null和undefined是所有类型的子类型,也就是可以把 null和undefined赋值给任何类型的变量。
// null和undefined赋值给string
let str:string = "666";
str = null
str= undefined
// null和undefined赋值给number
let num:number = 666;
num = null
num= undefined
但如果在TS的配置文件 tsconfig.json 中设置:"strictNullChecks":true
,那 null和undefined就只能赋值给自己的类型,以及void类型。
3、number 和 bigint
两者都表示数字,但是两者并不兼容,不能互相赋值。TS 中可以用 Number
表示的最大整数为 2^53 - 1
,可以写为 Number.MAX_SAFE_INTEGER
。如果超过了这个界限,可以用 BigInt
来表示,它可以表示任意大的整数。
let big: bigint = 100n;
let num: number = 6;
big = num; // 不兼容 会报错
num = big;// 不兼容 会报错
4、Array
TS中定义数组的方式有两种:
// 数组名:元素类型[]
let arr:string[] = ["1","2"];
// 数组名:Array<元素类型>
let arr2:Array<string> = ["1","2"];
当数组内的元素类型不止一种时,可以定义联合类型数组,或设置数组类型为 any:
// 数组元素可以为数字或字符串
let arr:(number | string)[];
// 数组元素为任意类型
let arr2:any[];
还可以结合接口来指定对象成员的数组:
// interface是接口,后面会讲到
interface Arrobj{
name:string,
age:number
}
let arr3:Arrobj[]=[{name:'jimmy',age:22}]
5、Tuple(元组)
元组是TS中特有的类型,定义方式类似于数组,就像被限制住元素个数、类型和顺序的数组:
// 定义元组 类型必须顺序匹配且个数必须为2
let x: [string, number];
x = ['hello', 10]; // OK
x = ['hello', 10,10]; // 越界了 Error
x = [10, 'hello']; // 类型不匹配 Error
元组中的元素可以通过下标访问,也可以通过解构赋值来访问元素:
// 定义元祖
let employee: [number, string] = [1, "Semlinker"];
// 数组下标访问
let n = employee[0];
// 解构赋值来访问元组元素 按顺序一一对应
let [id, username] = employee;
// 解构赋值数量不能多于元组的元素数量
let [id, username, age] = employee; // Error
定义元组时,我们也可以通过在元素后面加 ?
来声明可选元素:
// 定义元组 第二个元素是可选元素
let optionalTuple: [string, boolean?];
// 赋值元组 两个元素都赋值
optionalTuple = ["Semlinker", true];
// 赋值元组 只赋值第一个元素 第二个可选元素不赋值
optionalTuple = ["Kakuqo"];
定义元组时,元祖类型的最后一个元素可以表示剩余元素,以数组的形式存放多出来的元素,表示该元组是开放的,除了固定元素,可以有零个或多个额外的剩余元素:
// 定义元组 第二个元素是剩余参数
// 这里的剩余参数只能是 string 类型 因为剩余参数数组是 string 数组
type RestTupleType = [number, ...string[]];
// 赋值元组 除了第一个值 剩下的都存放到 剩余参数数组中
let restTuple: RestTupleType = [666, "Semlinker", "Kakuqo", "Lolo"];
在TS中,我们可以给元组加上 readonly 关键字,使其变为只读的,不允许进行修改:
// 声明只读类型的元组
const point: readonly [number, number] = [10, 20];
// 可读取
var n = point[0]
// 不可修改
point[0] = 1; // 会报错 Cannot assign to '0' because it is a read-only property.
6、void
void 表示没有任何类型,赋值时只能赋予null 或 undefined。声明一个void类型的变量,没有任何意义,一般只用于当函数没有返回值时,才会用到void。
// 返回值类型定义为 void 表示没有返回值
function fun(): void {
console.log("this is TypeScript");
};
fun();
7、never
never
类型表示的是那些永不存在的值的类型,一般用于两种情况:① 函数运行时抛出了异常,那么这个函数就永远不存在返回值,就是never。② 当函数中出现了死循环的代码,那么这个函数页永远不存在返回值,就是never。
never
类型同null
和undefined
一样,也是任何类型的子类型,也可以赋值给任何类型。但是没有类型是never
的子类型或可以赋值给never
类型(除了never
本身之外),即使any
也不可以赋值给never
。
let ne: never;
let nev: never;
let an: any;
ne = 123; // Error
ne = nev; // OK
ne = an; // Error
8、unknown
unknown 与 any 类似,任何类型都可以赋值给它,两者唯一的区别在于:any类型的值,可以赋值给任何类型的变量,而 unknown 类型的值,只能赋值给 unknown 和 any 类型:
let notSure: unknown = 4;
let uncertain: any = notSure; // OK
let notSure: any = 4;
let uncertain: unknown = notSure; // OK
let notSure: unknown = 4;
let uncertain: number = notSure; // Error
9、object
object 表示的是所有非基本类型的数据,也就是不能把number、string、boolean、symbol等 基本类型赋值给 object,只能接收复杂数据类型:
let obj: object;
obj = 1; // error
obj = 'a'; // error
obj = true; // error
obj = null; // error
obj = undefined; // error
obj = {}; // ok
四、函数
1、函数声明
// 函数名(形参1: 数据类型,形参2: 数据类型): 返回值的数据类型
// x-数值型 y-数值型 返回值-数值型
function sum(x: number, y: number): number {
return x + y;
}
// 或
const sum = (x: number,y: number): number => {
return x + y;
}
2、可选参数
如果函数的部分参数,是非必须的,被称为可选参数,TS中通过在参数名后面加 ?
来标明,而且可选参数必须位于必需参数的后面:
// 可选参数 lastName?: string
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
// 传递可选参数
let tomcat = buildName('Tom', 'Cat'); // Tom Cat
// 不传递可选参数
let tom = buildName('Tom'); // Tom
3、参数默认值
在TS中可以给函数的参数设置默认值,如果使用函数时,未传递该参数,则使用默认值,如果传递了该参数,则传递的值覆盖默认值:
// 参数默认值 lastName: string = 'Cat'
function buildName(firstName: string, lastName: string = 'Cat') {
return firstName + ' ' + lastName;
}
// 传递lastName参数 覆盖默认值
let tomcat = buildName('Tom', 'Cat222'); // Tom Cat222
let tom = buildName('Tom'); // Tom Cat
4、剩余参数
在TS中如果不确定函数的参数数量,我们可以通过设置以数组+扩展运算符的方法来接收剩余参数,前面写的参数,会跟实参一一对应,剩下的参数会都会放到剩余参数数组中:
// 剩余参数 ...items: any[]
function push(array: any[], ...items: any[]) {
items.forEach(function(item) {
array.push(item);
});
}
let a = [];
// a 对应第一个参数array 剩余的参数都存放到 items 中
push(a, 1, 2, 3);
5、函数重载
函数重载是指使用相同名称和不同参数(数量或类型不同)、不同的返回值类型创建多个函数类型定义,它们不会被覆盖,只是为同一个函数体提供多个函数类型定义,这样就能根据传入的参数不同,确认不同的返回值类型:
// 联合类型 type
type Types = number | string
// 函数重载 1
function add(a:number,b:number):number;
// 函数重载 2
function add(a: string, b: string): string;
// 函数重载 3
function add(a: string, b: number): string;
// 函数重载 4
function add(a: number, b: string): string;
// 函数体
function add(a:Types, b:Types) {
if (typeof a === 'string' || typeof b === 'string') {
return a.toString() + b.toString();
}
return a + b;
}
// 参数是两个 string 匹配函数重载2 返回值为 string
const result = add('Semlinker', ' Kakuqo');
// 可以调用string的内置API
result.split(' ');