前言
1.什么是Typescript?
TypeScript
并不是一门新的编程语言,它是Javscript
的超集,即在JavaScript
语言的基础上添加了语言约束:可选的静态类型和基于类的面向对象编程。其实就是添加了静态类型检查,有了约束可以让我们在开发过程中减少错误代码的书写。
TypeScript
和JavaScript
的关系如下:
TypeScript
和JavaScript
的区别:
TypeScript | JavaScript |
---|---|
强类型,支持静态和动态类型 | 弱类型,没有静态类型 |
JavaScript的超集,适用于解决大型项目的代码复杂性 | 脚本语言,用于开发动态网页 |
可在编译期间发现并纠正错误 | 解释性语言,只能在运行时发现错误 |
编译成JS后,浏览器才理解 | 可以直接在浏览器中使用 |
支持模块、泛型和接口 | 不支持模块、泛型和接口 |
2.两分钟上手TS开发
“工欲行其事,必先利其器”,说的就是在做事情之前,要做好所有的准备。同样的,我们要学习TS开发,必须先安装语言环境和编辑器工具。
安装TypeScript
有两种方式可以获取TypeSscript
工具:
- 通过NPM进行安装
- 安装VScode的TypeScript插件
(1)NPM安装:
npm install -g typescript
(2)验证TS安装
tsc -v
# Version 4.2.4
(3)构建TS文件
在编辑器中构建一个TS文件test.ts:
function addNum(num1:num,num2:num){
return num1 + num2;
}
console.log(addNum(1,2));
//3
(4)编译代码:
tsc test.ts
编译得到JS代码:
"use strict";
function addNum(num1, num2) {
return num1 + num2;
}
console.log(addNum(1, 2));
3.基础类型
数据类型 | 关键字 | 描述 |
---|---|---|
布尔值 | Boolean | 只有两个值:true和false。 |
数字类型 | Number | 双精度 64 位浮点值。它可以用来表示整数和分数。 |
字符串类型 | String | 一个字符系列,使用单引号(’)或双引号(")来表示字符串类型。反引号(`)来定义多行文本和内嵌表达式。 |
元组 | Tuple | 一个已知元素数量和类型的数组,各元素的类型不必相同。 |
枚举 | enum | 枚举类型用于定义数值集合。 |
任意类型 | any | 声明为 any 的变量可以赋予任意类型的值。 |
void | void | 用于标识方法返回值的类型,表示该方法没有返回值。 |
null | null | 表示对象值缺失。 |
undefined | undefined | 用于初始化变量为一个未定义的值 |
never | never | never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。 |
3.1 Boolean类型
只有两个值:true和false。
let isTrue: boolean = true;
3.2 Number类型
所有的数字都是浮点型,支持二进制、八进制、十进制以及十六进制字面量。
// 数字类型,所有数字都是浮点型
let decLiteral: number = 10;
let hexLiteral: number = 0xf00d;
3.3 String类型
TS可以使用双引号( ")或单引号(’)表示字符串。
// 字符串,表示文本数据类型
let username: string = "yichuan";
let like: string = `${yichuan} + FE`;
3.4 Array类型
数组操作有两种方式可以声明:
- 可以在元素类型后面接上 [],表示由此类型元素组成的一个数组。
- 使用数组泛型,Array<元素类型>。
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];
3.5 Tuple类型
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
// 元组
let tuple: [string,number];
tuple = ["wenbo",1];
TS元组和数组其实大致一样,唯一的区别就是数组中的元素类型必须相同,而元组可以存储不同类型的元素。甚至可以说元组是any类型的数组。
3.6 Enum类型
enum
类型是对JavaScript
标准数据类型的一个补充。枚举类型提供的一个便利是你可以由枚举的值得到它的名字。
// 枚举
// 默认情况下,枚举的元素编号是从0开始,也可以进行手动编号。
enum Color {Red, Green, Blue};
let c:Color = Color.Red;
3.7 Any类型
any
表示任意类型。
有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。
// Any
let notSure:any = 100.002;
notSure.toFixed();
let list3:any[] = ["zhaoshun","male",12];
其实,any类型是类型系统的*类型,因为任何类型都归结于any类型,是不是很*。*过了火,一个不恰当的比喻,JS是any类型的TS,允许对any类型的值进行各种操作,而无需编译校验。
3.8 Void类型
void
类型它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void
。
声明一个void类型的变量没有什么大用,因为你只能为它赋予null和undefined。
function showName():void {
console.log("your name is wenbo");
}
// 声明一个void类型的变量
let unusable: void = undefined;
3.9 Null 和 Undefined
TypeScript里,undefined和null两者各自有自己的类型分别叫做undefined和null。 默认情况下null和undefined是所有类型的子类型,可以把 null和undefined赋值给number类型的变量。
let u: undefined = undefined;
let n: null = null;
但是,当指定了--strictNullChecks
标记,null
和undefined
只能赋值给void和它们各自。
3.10 Object
object表示非原始数据类型(除number,string,boolean,symbol,null或undefined之外的类型)。
declare function create(o: object | null): void;
create({ prop: 0 }); // OK
create(null); // OK
create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error
3.11 Never
never类型表示的是那些永不存在的值的类型。
never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。 即使 any也不可以赋值给never。
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {
}
}
3.12 Unknown 类型
任何类型都可以被归为unknow类型,因此unknow也是ts类型中的*类型。
let value: unknown;
value = true; // OK
value = 18; // OK
value = "yichuan"; // OK
value = []; // OK
value = {}; // OK
value = Math.random; // OK
value = null; // OK
value = undefined; // OK
value = new TypeError(); // OK
value = Symbol("type"); // OK
我们看到对于value变量而言,所有的赋值都是正确的,就会感觉是不是发现和any好像没啥区别,真的是这样吗。当我们给赋值其他类型时,就会出现意想不到的问题,发现unknow类型只能被赋值给any类型和unknow类型本身,这就是跟any的区别。
let value: unknown;
let value1: unknown = value; // OK
let value2: any = value; // OK
let value3: boolean = value; // Error
let value4: number = value; // Error
let value5: string = value; // Error
let value6: object = value; // Error
let value7: any[] = value; // Error
let value8: Function = value; // Error
所以得到:只有能够保存任意类型值的容器才能保存 unknown
类型的值。
值得注意的是,TS
不允许我们对unknow
类型的值执行任何操作,必须得先执行类型校验后来确定使用值的范围。那么如何缩小unknow
值的范围呢?
很简单,有请我们的老朋友typeof
、instanceof
运算符和自定义类型保护函数,通过使用缩小类型范围的技术都有助于 TypeScript
的基于控制流的类型分析。
例如,通过if语句分支
function stringifyForLogging(value: unknown): string {
if (typeof value === "function") {
const functionName = value.name || "(anonymous)";
return `[function ${functionName}]`;
}
if (value instanceof Date) {
return value.toISOString();
}
return String(value);
}
通过使用自定义类型保护函数缩小 unknown 类型范围。
function isNumberArray(value: unknown): value is number[] {
return (
Array.isArray(value) &&
value.every(element => typeof element === "number")
);
}
const unknownValue: unknown = [15, 23, 8, 4, 42, 16];
if (isNumberArray(unknownValue)) {
const max = Math.max(...unknownValue);
console.log(max);
}
尽管 unknownValue
已经被归为 unknown
类型,请注意它如何依然在 if
分支下获取到 number[]
类型。
写在最后
我是前端小菜鸡,感谢大家的阅读,我将继续和大家分享更多优秀的文章,此文参考了大量书籍和文章,如果有错误和纰漏,希望能给予指正。