【青训营】- TypeScript入门之预备知识

516 阅读8分钟

准备开始向TS下手了,我们先不说TS该【怎么用】,而是先来看看【是什么】:TS与JS之前是什么关系?TS的编译过程是什么样的?什么是类型拓宽、收窄类?值空间、类型空间又是什么?不论你是刚学ts,还是已经在用ts,都值得一看!

开发环境准备

安装VSCode

安装Node.js

网上已经有很多很好的安装教程,这个就不细说了。

创建项目

初始化第一个TypeScript项目

新增一个【first-ts-project】文件夹,进入文件夹,执行

npm init -y

就能在文件夹创建一个package.json文件

image-20210822132648609

然后接着执行以下这个命令安装 typescript 最新稳定版

npm install -- save-dev typescript

如果想用尝鲜使用最新的typescript,可以执行下面这个命令

npm install --save-dev typescript@next 

创建tsconfig.json

方法一:利用VScode编辑器

  • 先创建一个index.ts文件,用VScode打开

  • 点击VScode底部TypeScript的版本号

  • 在弹出来的弹出框点击【创建tsconfg】即可

    image-20210822133648401

image-20210822133819966

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es2020",
        "jsx": "preserve",
        "strictFunctionTypes": true,
        "sourceMap": true
    },
    "exclude": [
        "node_modules",
        "**/node_modules/*"
    ]
}

方法二:利用命令行创建

node_modules/.bin/tsc   --init --locale zh-CN

image-20210822134240057

通过这种方法创建tsconfig.json包含所有编译器参数以及参数说明

image-20210822134309136

在TS的项目中,TS最终都会被编译JS文件执行,TS编译器在编译TS文件的时候都会先在项目根目录的tsconfig.json文件,根据该文件的配置进行编译,默认情况下,如果该文件没有任何配置,TS编译器会默认编译项目目录下所有的.ts、.tsx、.d.ts文件。

一些TS的工具

TS Playground

  • 可以在这上面直接测试ts代码
  • 也可以复制分享链接,把当前的代码分享给别人

image-20210822135102169

Equal<X, Y>

它可以用来判断两个类型是否相等

安装

npm install -- save-dev @type-challenges/utils

引入

import { Equal } from "@type-challenges/utils";

使用示例

type R = Equal<boolean,true | false>;

鼠标悬停在类型名上查看两个类型是否相等

image-20210822140046811

Playground中可以直接引入使用 image-20210822140437961

预备知识

TS与JS的关系

  • TypeScript是JavaScript的超集
  • TypeScript提供所有JavaScript特性。并在其上层增加了TypeScript类型系统
  • 这个类型系统被设计为“可选的”这就意味着:所有合法的JavaScript代码都是合法的TypeScript代码. (你直接把js后缀文件,改成ts也是合法的)

image-20210821212312451

TS的编译过程

  • ”TS的类型检查” 与 ”生成JS” 是两个独立的过程;
  • 类型检查出错不影响生成JavaScript代码;

VS Code是指我们当前用的编辑器(也可以用其他编辑器)

image-20210822194839460

类型系统

结构类型系统( Structural Type System ) 通过类型的实际结构确定两个类型是否相等或兼容

采用这种系统的语言有

TypeScript, Haskell, OCaml, Go,...

名义类型系统( Nominal Type System ) 通过类型的名称确定两个类型是否相等

采用这种系统的语言有

C, C++, Java, C#, Rust

知识点

TS采用的是结构类型系统

类型注解

TS的类型注解放在后面,加单冒号

function log(message: string): void

类型与集合的关系

  • 空集( Empty Type )

    never
    
    
  • 单元素集合( Unit Type )

    Null = {null}
    Undefined = {undefined}
    Literal Type(字面量类型,"a",1,true)
    
  • 有限集合

    Boolean = {true, false}
    
  • 无限集合(近似)

    String = {a','b',...,'hello',...}
    Symbol = {Symbol(...),...}
    BigInt = {...,-1n, 0n, 1n,...}
    Number = {-Infinity,-(2^53 - 1.),... 0,...,+2^253 - 1, Infinity}和NaN
    
  • 全集( Universal Set )

    image-20210822142431448

类型联合与交叉

从名字看

联合类型( Union Types ) VS 交叉类型( Intersection Types )

集合并集( Union ) VS 集合交集( Intersection )

从写法看

TS写法

A I B(A或B) A & B(A与B)

数学写法

A U B(A并B) A ∩ B(A交B)

从图示看

image-20210822142906789

类型别名

类比:

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

可以理解为"某个东西"的名字,方便记忆,也更具有描述性

image-20210822143638756

知识点:

  • 类型别名和let变量类似,也采用块级作用域。所以,同一个作用域内不能重名

image-20210822201309695

  • 内层类型别名会隐藏外层同名类型

image-20210822201322737

类型拓宽、收窄类型拓宽( Type Widening )

类型拓宽( Type Widening )

当你把用字面量赋值给let、 var变量时,TS不用字面量类型(单元素集合)作为该变量的类型。而是从字面量类型拓宽到相应的更宽泛的类型。这个过程叫做类型拓宽

类型收窄( Type Narrowing )

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

知识点:

  • TS试图在类型确定性与灵活性之前取得平衡

  • TS提供一系列方法来帮助收窄类型,以提高类型的确定性:

    null check、as const、instanceof、 typeof、属性检查、Tagged Union、用户类型守卫( User-defined Type Guard )、代码流分析

示例

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

左边是【拓宽】,右边是【收窄】

image-20210821214444860

值空间与类型空间

类型空间

是在编译器存在的各种类型,这个空间是由TS的tsc编译器创建的,里面有各种类型,ts会根据代码去实例化各种类型;

值空间

值空间里面存在各种值,这个空间是由JS 的引擎创建的,里面存在各种运行时的变量或者常量;

image-20210821214614477

注意:

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

image-20210822152528649

正确的做法

interface IPoint {
    x:number;
    y:number;
}

const p:IPoint = {x:0,y:0};

class Point implements IPoint{
    constructor(
        public x:number,
        public y:number
    ){}
}

if(p instanceof Point){}

小知识

  • JavaScript 中的类型其实是值的类型(不仅仅是 JavaScript,任何动态类型语言都是如此,这也是动态类型语言的本质)

  • Typescript 中的类型其实是变量的类型(不仅仅是 Typescript,任何静态类型语言都是如此,这也是静态类型语言的本质)

解析

  • 对于 JavaScript 来说,一个变量可以是任意类型。

如以下示例,a最初是Number 类型,后面还可以改为【字符串类型】、【对象类型】、【数组类型】,变量a并没有固定类型;

image-20210822150158305

image-20210822150607159

  • 对于 Typescript 来说, 一个变量只能接受和它类型兼容的类型的值。

如以下示例,我们不能将 string 类型的值赋值给变量b, 因为 string 和 number 类型不兼容;

image-20210822150805053

image-20210822151026119

一旦一个变量被标注了某种类型,那么其就只能接受这个类型以及它的子类型。

如何判断符号是在哪个空间?

  • 转译后消失的符号→类型空间
  • 作为类型注解、别名的符号→类型空间( type T = typeof Person; const p: Person )
  • 类型断言后的符号→类型空间( target as/is HTMLElement )
  • const, let, var后面的符号→值空间
  • class, enum,namespace后的符号-→值空间+类型空间

另外,有一些操作符在两个空间都存在,但是含义完全不同:

typeof

  • 在值空间,typeof返后面表达式对应的JavaScript类型的字符串表示
'string', 'number', 'bigint', 'boolean', 'symbol', 'undefined', 'object', 'function'
  • 在类型空间,typeof返回标识符对应的TypeScript类型

image-20210822153903912

[] (索引访问操作符 Indexed Access Operator )

  • 在值空间, val[field]或val.field返回val对应属性的值

  • 在类型空间,Type[T]返回对应T的TS类型

    image-20210822154424177

    string, number的子集,TS4.4之后增加了symbol和template string pattern

this关键字

  • 在值空间,this指...比较复杂(这里就先不展开了)
  • 在类型空间,this可以作为类方法的返回值来实现链式调用

&|运算符

  • 在值空间表示“"按位与”和“按位或" (Bitwise AND, OR)
  • 在类型空间表示类型的交叉和联合

const

  • 在值空间用来声明常量
  • 在类型空间与as连用,即"as const"常量断言,收窄类型

extends

  • 在值空间用于定义子类( class A extends B )
  • 在类型空间用来进行类型约束( T extends number )或接口继承 ( interface A extends B )

in

  • 在值空间用于for循环( for (key in object) {...} )和判断属性是否存在( 'name' in person )
  • 在类型空间用于映射类型的key的声明( Mapped Type )

总结

本篇主要都是一些概念知识,暂时看不懂可以先记着,后面的文章中都会用到,甚至是以后使用TS的过程中遇到的一些问题,这些或许都可以用以解答为什么。

结语

字节青训营

本节课的讲师:字节前端—王韦华

如以上有错误的地方,请在评论区中指出!


小可爱看完点个赞再走吧!😗