【青训营】- TypeScript初识(开发环境|基础知识)

693 阅读9分钟

写在前边~

✏️TypeScript是什么

打开TypeScript中文网站,最大的图字:TypeScript——JavaScript的超集

QQ截图20210820131930.jpg
打开官方网站,会看到这样的介绍——TypeScript 是具有类型语法的 JavaScript。 TypeScript 是一种建立在 JavaScript 之上的强类型编程语言,可为您提供任何规模的更好工具。

在我理解来看,TypeScript是JavaScript的“升级版”和“智能版”,可以让开发者在编写JS代码时提高效率。

✏️TypeScript开发环境

TypeScript的开发环境需要两件事:

  1. 安装VSCode
  2. 安装Node.js
    安装Node.js有两种选择,可以选择安装nvm(可自由选择使用不同的node.js版本),也可以直接在官网安装。

提前准备好开发环境,就可以愉快的开始编写TypeScript了~

TypeScript入门

✏️开始我的第一个TypeScript项目~

创建项目

在命令窗口输入,初始化第一个项目

   mkdir first-ts-project && cd first-ts-project   //创建名为first-ts-project的文件夹并进入
   npm init -v                                     //初始化package.json文件
   npm install --save-dev typescript               //安装最新稳定版
   npm install --save-dev typescript@next          //安装最新版本(任选一个版本就可以了)

创建tsconfig.json

方法1:

QQ截图20210819132050.jpg

方法2:
node_modules/.bin/tsc --init --locale-zh-CN
通过这种方法创建tsconfig.json包含所有编译器参数以及参数说明

工具

👉 TS Playground
官方网站提供的一个可以在线编译TS的工具
⭐️ 亮点:
鼠标悬停在类型名上查看其类型

👉 Equal<X,Y>
⭐️ 亮点:
1.在TS中可以使用Equal<X,Y>来比较两个类型是否相等,相等返回true,否则返回false
2. import{Equal}from'@type-challenges/utils'
鼠标悬停在类型名上查看两个类型是否相等

✏️TypeScript预备知识

TS与JS的关系

前文中也有介绍到它们两者之间的关系 TypeScript是JavaScript的超集。
TypeScript提供所有JavaScript特性。并在其上层增加了TypeScript类型系统。

简单来说:只要JavaScript中能干的事情,TypeScript也能干,还能干的更好更快。

TS的编译过程

‘TS的类型检查’与‘生成JS’是两个独立的过程,类型检查出错不影响生成JavaScript代码!

类型系统

编程语言中,类型系统分为如下两种:
1. 结构类系统:通过类型的实际结构确定两个类型是否相等或兼容(TypeScript、Haskell、Go、...)
2. 名义类型系统:通过类型的名称确定两个类型是否相等
(C、C++、Java、...)

TS采用结构类型系统

类型注解

不同语言的类型注解语法:

//c++ 放在前面
int print(const char*, ... );

//TS 放在前面,加单冒号
function log(message: string): void

类型与集合

图示:

QQ截图20210820150512.jpg

类型别名

在JS中使用let、constructor、var声明变量或常量
在TS中可以用type为类型声明别名

类型别名和let变量类似,采用块级作用域,所以同一个作用域内不能重名;同样的,内层类型别名会隐藏外层同名类型

类型拓宽、收窄

  1. 类型拓宽:
    当使用字面量赋值给let、bar变量时、TS不用字面量类型作为该变量的类型,而是从字面了类型拓宽到相应更宽泛的类型,这个过程叫做类型拓宽。

  2. 类型收窄:
    在某些情况下,TS可以更加确定变量的类型,此时它会将变量类型收窄。

知识点:TS试图在类型确定性与灵活性之前取得平衡

TS提供一系列方法来帮助收窄类型,以提高类型确定性:null check、as const、instanceof、typeof、属性检查、Tagged Union、用户类型守卫、代码流分析

用let、var声明时,TS认为变量会发送改变,所以将类型推断为相对宽泛的类型 用const声明常量时,TS知道常量不会改变,会将类型推断为最窄的字面量类型

例如:

举个栗子类型
let a = 'hello'string
const a = 'hello'“hello”

⭐️ 这里的a分别由let、和const声明,由let声明的a会由TS推断为相对宽泛的类型,“hello”是string的子集

值空间与类型空间

在TS中:

QQ截图20210820164518.jpg
注意:

  1. 只包含类型声明的namespace不会产生JS代码,不会引入入变量
  2. instanceof操作符只作用于值空间

>类型空间中的类型包含TS中特有的类型(type、interface)和TS与JS中共有的类型
>值空间中包含JS中特有的类型(const、let、var)和TS与JS中共有的类型

⭐️TS转义为JS代码后,值空间中没有的符号转义后会被擦除(类似Java中类型擦除)

如何判断符号在值空间还是类型空间?

1.转义后消失的符号——>类型空间
2.作为类型注解、别名的符号——>类型空间
(type T = ypeof Person; const p:Person )
3.类型断言后的符号——>类型空间(target as/is HTMLElement)
4.const,let,var后面的符号——>值空间
5.class,enumerate,namespace后面的符号——>值空间+类型空间

有一些操作符在值空间和类型空间都存在,但是含义完全不同,如:
typeof
>在值空间,typeof返回表达式对应的JavaScript类型的字符串表示('string' 'number' 'bigint' 'boolean' 'symbol' 'undefined' 'object' 'function' )
>在类型空间,typeof返回标识符对应的TypeScript类型
还有如下:
[]
this
$|
const
extends
in

✏️TypeScript基础知识

TS中类型层次

123456.jpg

最上层为全集Top Type,最下层Never为空集Bottom Type

下层类型的值可以赋给上层类型的变/常量
∴unknown类型的变/常量可以指向任何类型的值
∴不存在never类型的变量(never是空集,是任何集合的子集)

any

1.any很特殊,正如其名,既是Top Type也是Bottom Type; any类型的变/常量和其他类型变/常量可以相互赋值
但是正因如此any是类型不安全的、无语言服务的,要尽量避免使用
2.any具有传染性:它会使他所触及的地方变得不安全,所以TS在3.0引入了类型安全的unknown作为Top Type
3.any会隐藏bug
因为没有类型信息,即便错误使用,也没有任何报错;比如当any类型使用一个不存在的方法时,系统并不会报错
4.any会隐藏代码设计细节:丢失了对数据类型的设计

⭐️如何避免使用any造成一些不必要的麻烦: 在tsconfig中开启strict模式或禁止隐式any

{
        "compilerOptions": {
        "strict": true,
        "noImplicitAny": true  //开启noImplicitAny
    }

unknown

1.unknown必须显示注解,TS不会把任何值推导为unknown
let a: unknown = 30;//typeof a = unknown
2.unknown值只能进行等于和不等于比较,否则系统报错
3. 只有类型收窄后能进行相应运算或函数调用,否则会报错

如果无法预知类型,不要用any,用unknown,收窄类型后再使用

布尔类型(boolean)

布尔类型只有两个元素true和false

  1. let,var变量会被拓宽成boolean类型,是const常量就是对应字面量类型
let a = true; //typeof a = boolean
var b = false; //typeof b = boolean
const c = true; //typeof c = true
  1. 值得注意的是,true和false的联合类型,会被反推回boolean
    let d: true | false = true; //g会被反推为boolean类型

number类型

number包括:整数、浮点数、±Infinity(正负无穷),NaN(Not a Number)

bigint类型

bigint是新引入的类型,可以表示任意大小的整数,number范围[-(2^53-1),2^53-1] bigint字面量是在数字后面加小写“n”,支持+、-、*、/、%、**运算

bigint不能和number混合运算,需要显示转换

字符串类型(string)

    type Dir = 'north'|'south'
    type Direction = Dir | Capitalize<Dir>
    //type Direction = Dir |'North'|'South'
    

字符串字面量联合常用区分数据类型

符号类型(symbol)

symbol是ES2021引入的新的语言特性

  1. let、var声明的变量推导成symbol类型,unique symbol必须是const常量
  2. const常量推导为unique symbol,也可以注解成unique symbol
import{Equal}from'@type-challenges/utils'

let a = Symbol('a');                  //typeof a = symbol
var a1 = Symbol('a');                 //typeof a1 = symbol
let a2:unique symbol  = a1;           //Error
const b1:unique symbol  = Symbol('b');//"unique symbol b1"
const b1x = Symbol('b');             //"unique symbol b1x"
type x = Equal<typeof b1,typeof b1x>;//false

unique symbol不是一个类型,而是一组类型。比如:unique symbol b1和unique symbol b1x是两个类型

⭐️unique symbol

  1. 与其他字面量不同,unique symbol类型无法直接应用,必须通过"typeof 常量"的形式引用
  2. 将unique symbol赋值给另一个const是,类型会拓宽为symbol,如果不希望拓宽,需要注解为对应常量的typeof

对象类型(object)

对比:JS中定义对象和定义对象类型与TS中获取对象keys和获取对象类型keys

123456.jpg

数组类型(Array)

1.const数组不会收窄,因为收窄就变成tuple类型了
2.TS无法推断空数组类型,只能推断为any[]
3.当往数组中添加元素后,TS可以分析代码,推断出数组类型

数组有两种注解方式

  1. T[]
  2. Array接口泛型

元组(Tuple)

元组(Tuple)时数组的子类型,元组各索引位上的元素类型是确定

因为元组的创建方式和数组是一样的,所以元组必须注解

let a: [number] = [1];
let b: [string,string,number] = ['a','b',123];
//如果123不是number类型,会报错显示元素类型不匹配

⭐️[...string[]]等价于string[],但[string,...string[]]不等价于string[],前者至少包含一个元素

枚举(Enum)

枚举本质上是一种映射,会在值空间产生一个包含该映射的对象

123456.jpg

  1. 未显示赋值的枚举自动从0自增赋值,显示赋值为整数的枚举(存在双向映射
  2. 显示赋值字符串的枚举不存在反向映射

枚举合并:枚举可以拆分成多段,可以和同名namespace合并

常量枚举

常量枚举不会在值空间创建变量,所有引用常量枚举的地方都被替换为对应的值(但是可以通过preseverConstEnum编译器选项来控制),方便调试

void,never

⭐️TS中
void类型:函数没有显式返回值
never类型:函数无法返回

⭐️JS中
void是一个一元操作符:它执行后面的表达值,然后无条件返回undefined

写在最后~

到这里,TypeScript基础知识笔记完成啦。
初识TypeScript,了解到它的一些特性和优点,让我觉得TS算得上一门“智能化”语言,在上课学习时,看到最多的就是TS会识别判定变量类型,这样我们在JS开发过程中遇到的变量因为类型不同不能运算的问题就能很好的解决。
TypeScript最近有越来越多的人推荐使用,各大互联网公司招聘要求也会添加这一门语言,那么TypeScript必然就会有它独特的优点,也有待我以后更深层次的去学习和了解这门语言。
如有记录错误,欢迎大家指出!!