准备开始向TS下手了,我们先不说TS该【怎么用】,而是先来看看【是什么】:TS与JS之前是什么关系?TS的编译过程是什么样的?什么是类型拓宽、收窄类?值空间、类型空间又是什么?不论你是刚学ts,还是已经在用ts,都值得一看!
开发环境准备
网上已经有很多很好的安装教程,这个就不细说了。
创建项目
初始化第一个TypeScript项目
新增一个【first-ts-project】文件夹,进入文件夹,执行
npm init -y
就能在文件夹创建一个package.json
文件
然后接着执行以下这个命令安装 typescript 最新稳定版
npm install -- save-dev typescript
如果想用尝鲜使用最新的typescript,可以执行下面这个命令
npm install --save-dev typescript@next
创建tsconfig.json
方法一:利用VScode编辑器
-
先创建一个
index.ts
文件,用VScode打开 -
点击VScode底部TypeScript的版本号
-
在弹出来的弹出框点击【创建tsconfg】即可
{
"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包含所有编译器参数以及参数说明
在TS的项目中,TS最终都会被编译JS文件执行,TS编译器在编译TS文件的时候都会先在项目根目录的
tsconfig.json
文件,根据该文件的配置进行编译,默认情况下,如果该文件没有任何配置,TS编译器会默认编译项目目录下所有的.ts、.tsx、.d.ts
文件。
一些TS的工具
- 可以在这上面直接测试ts代码
- 也可以复制分享链接,把当前的代码分享给别人
它可以用来判断两个类型是否相等
安装
npm install -- save-dev @type-challenges/utils
引入
import { Equal } from "@type-challenges/utils";
使用示例
type R = Equal<boolean,true | false>;
鼠标悬停在类型名上查看两个类型是否相等
Playground中可以直接引入使用
预备知识
TS与JS的关系
- TypeScript是JavaScript的超集
- TypeScript提供所有JavaScript特性。并在其上层增加了TypeScript类型系统。
- 这个类型系统被设计为“可选的”这就意味着:所有合法的JavaScript代码都是合法的TypeScript代码. (你直接把js后缀文件,改成ts也是合法的)
TS的编译过程
- ”TS的类型检查” 与 ”生成JS” 是两个独立的过程;
- 类型检查出错不影响生成JavaScript代码;
VS Code是指我们当前用的编辑器(也可以用其他编辑器)
类型系统
结构类型系统( 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 )
类型联合与交叉
从名字看
联合类型( 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)
从图示看
类型别名
类比:
- 在JS中: 可以用
let、const、 var
声明变量或常量 - 在TS中: 可以用
type
为类型声明别名
可以理解为"某个东西"的名字,方便记忆,也更具有描述性
知识点:
-
类型别名和let变量类似,也采用块级作用域。所以,同一个作用域内不能重名
- 内层类型别名会隐藏外层同名类型
类型拓宽、收窄类型拓宽( 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知道常量是不会改变的,会将类型推断为最窄的字面量类型
左边是【拓宽】,右边是【收窄】
值空间与类型空间
类型空间
是在编译器存在的各种类型,这个空间是由TS的tsc编译器创建的,里面有各种类型,ts会根据代码去实例化各种类型;
值空间
值空间里面存在各种值,这个空间是由JS 的引擎创建的,里面存在各种运行时的变量或者常量;
注意:
- 只包含类型声明的namespace不会产生JS代码,不会引入变量
- instanceof操作符只作用于值空间
正确的做法
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并没有固定类型;
- 对于 Typescript 来说, 一个变量只能接受和它类型兼容的类型的值。
如以下示例,我们不能将 string 类型的值赋值给变量b, 因为 string 和 number 类型不兼容;
一旦一个变量被标注了某种类型,那么其就只能接受这个类型以及它的子类型。
如何判断符号是在哪个空间?
- 转译后消失的符号→类型空间
- 作为类型注解、别名的符号→类型空间( 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类型
[] (索引访问操作符 Indexed Access Operator )
-
在值空间, val[field]或val.field返回val对应属性的值
-
在类型空间,Type[T]返回对应T的TS类型
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的过程中遇到的一些问题,这些或许都可以用以解答为什么。
结语
本节课的讲师:字节前端—王韦华
如以上有错误的地方,请在评论区中指出!
小可爱看完点个赞再走吧!😗