阅读 180

【青训营】- TypeScript入门之开发环境及预备知识

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

本文同时参与掘力星计划,赢取创作大礼包,挑战创作激励金

前言

我们系统程序的漏洞就叫 bug。世界上第一个 bug ,是 1946 年霍普发现了第一个电脑上的 bug,竟然是一只飞蛾“臭虫”。解决这些问题的过程叫做捉虫、调试,也就是 Debug。

开发环境准备

网上已经有很多详细的安装教程!

安装VSCode

QQ截图20211013161511.png

安装Node.js

QQ截图20211013161811.png

创建项目

初始化一个 TypeScript 项目

新建一个【first-ts-project】文件夹,进入文件夹,在终端上执行

npm init -y
复制代码

就能在文件夹创建一个package.json文件 QQ截图20211014153436.png typescript 最新稳定版

npm install -- save-dev typescript
复制代码

最新的typescript

npm install --save-dev typescript@next 
复制代码

创建tsconfig.json

方法一:在VScode编辑器上先创建一个index.ts文件,用VScode打开;点击VScode底部TypeScript的版本号,在弹出来的弹出框点击【创建tsconfg】即可。 QQ截图20211014161733.png

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

方法二:利用命令行

node_modules/.bin/tsc   --init --locale zh-CN
复制代码

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

工具

TS playground

TS Playground QQ截图20211014155804.png

Equal<X, Y>

Equal<X, Y> QQ截图20211014155913.png

预备知识

TS与JS的关系

QQ截图20211014112134.png

  • TypeScript是JavaScript的超集

  • TypeScript提供所有JavaScript特性。并在其上层增加了TypeScript类型系统

  • 这个类型系统被设计为“可选的”这就意味着:所有合法的JavaScript代码都是合法的TypeScript代码。

TS的编译过程

  • ‘TS的类型检查’ 与 ‘生成JS ’是两个独立的过程;

  • 类型检查出错不影响生成JavaScript代码;

QQ截图20211014112520.png

类型系统

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

TypeScript, Haskell, OCaml, Go,...
复制代码

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

C, C++, Java, C#, Rust,...
复制代码

知识点TS采用的是结构类型系统

结构类型系统

//结构类型系统:只要两个结构中有相同的函数就OK
class Foo {
  public hi() {
    console.log('hi');
  }
}
class Bar() {
  public hi() {
    console.log('Hello');
  }
}
//new一个Foo实例赋值给变量a
const a: Foo = new Foo();
//将a赋值给Bar实例再赋给b
const b: Bar = a;
//调用b上的hi()方法
b.hi(); //Works!
复制代码

名义类型系统

#include<iostream>
//声明两个一样的类
class Foo {
    public:
      void hi() {
          std::cout << "Hi" << std::endl;
      }
};
class Bar {
    public:
      void hi() {
          std::cout << "Hello" << std::endl;
      }
};
int main() {
    Foo foo;
    Foo &fooRef = foo;
    //Error: type 'Bar' cannot
    //bind to a value of unrelated type 'Foo'
    //将foo变量赋值给bar引用,在赋值过程中,编译器就会报错,因为两个类型是完全不相关的。名字不同就不行
    Bar &bar = foo;
    return 0;
}
复制代码

类型注解

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

C++放在前面

int printf(const char*,...);
复制代码

Objc放在前面,加括号

- (id)initWithInt:(int)value;
复制代码

Julia放在后面,加双冒号

commission(sale::Int,rate::Float64)::Float64
复制代码

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 )

QQ截图20211014115519.png

类型联合与交叉

QQ截图20211014115659.png

类型别名

类比

  • 在JS中: 可以用let、const、 var声明变量或常量

  • 在TS中: 可以用type为类型声明别名

都可以理解为“某个东西”的名字,可以方便记忆,更具有描述性。

// JS 声明变量或常量
let ID= 123;
cconst PI = 3.14;
var myPI = PI;

//TS 为类型声明别名
type ID = string;
type User = {
    id:ID;
    name:string;
}
复制代码

知识点

  • 类型别名和let变量类似,也采用块级作用域。所以,同一个作用域内不能重名。
type User = { 
    id:ID;
    name:string;
}

type User = { }
复制代码
  • 内层类型别名会隐藏外层同名类型
type User = { 
    id:ID;
    name:string;
}

//块级作用域
{
type User = {
    id:ID;
    nname:string;
 }
}
复制代码

类型拓宽、收窄

类型拓宽( 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知道常量是不会改变的,会将类型推断为最窄的字面量类型

左边是类型拓宽 右边是类型收窄 QQ截图20211014142930.png

值空间与类型空间

  • 类型空间是由TS的编译器tsc创建的,里面存在各种类型。tsc会根据代码实例化各种类型。

  • 值空间是后JSEngine 创建的 里面存在各种运行时的值。

QQ截图20211014143430.png

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

  • 转译后消失的符号→类型空间

  • 作为类型注解、别名的符号→类型空间( type T = typeof Person;T就是在类型空间 const p: Person;T就是在类型空间)

  • 类型断言后的符号→类型空间( target as/is HTMLElement;as/is后面的符号就是在类型空间的)

  • const, let, var后面的符号→值空间

  • class, enum,namespace后的符号→值空间+类型空间

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

typeof

在值空间,typeof返回后面表达式对应的JavaScript类型的字符串表示:

'string', 'number', 'bigint', 'boolean', 'symbol', 'undefined', 'object', 'function'
复制代码

在类型空间,typeof返回标识符对应的TypeScript类型 QQ截图20211014144318.png

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

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

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

QQ截图20211014145150.png

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 )

结语

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

小可爱们看完点个赞再走一走~~

文章分类
阅读
文章标签