TypeScript 入门

ts的优缺点

1、优点
代码的可读性和可维护性:举个🌰看后端某个接口返回值,一般需要去network看or去看接口文档,才知道返回数据结构,而正确用了ts后,编辑器会提醒接口返回值的类型,这点相当实用。

在编译阶段就发现大部分错误,避免了很多线上bug

增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等

2、缺点
有一定的学习成本,需要理解接口(Interfaces)、泛型(Generics)、类(Classes)、枚举类型(Enums)等前端工程师可能不是很熟悉的概念

会增加一些开发成本,当然这是前期的,后期维护更简单了

一些JavaScript库需要兼容,提供声明文件,像vue2,底层对ts的兼容就不是很好。

ts编译是需要时间的,这就意味着项目大了以后,开发环境启动和生产环境打包的速度就成了考验
可以看看Deno 内部代码将停用 TypeScript,并公布五项具体理由


Typescript 是什么?

如图

  • Typescript 是 JavaScript 的超集,两者是所属关系。
  • Typescript 是 JavaScript 的增强,包含 JavaScript 的最新特性,非常适合创建大型项目
  • Typescript 是静态语言与动态语言 JavaScript 不同,TS 是和 JS 都是弱类型语言
  • Typescript 也是前端的趋势,各大著名的前端框架都使用了 TS 重构,如 Vue, React 等

下载安装及使用

  • 本地环境需要先下载 node vscode,随后打开 vscode 终端,使用 npm install -g typescript 即可
  • tsc -v 查看版本号,这份教程是最新的 typescript 4.0
  • 建议安装 TSlint 插件规范代码
  • 编写 TS 文件代码,使用 tsc xx.ts 命令运行 ts 文件,运行 ts 文件后会生成相应的 js 文件,这个 js 文件时 tsc 将 xx.ts 代码编译成 xx.js的代码
  • tsc –watch xx.ts 自动监测编译代码

动态语言和静态语言的差别

  • 静态语言在编写代码的时候就能发现潜在的错误.
  • 静态语言更容易读懂代码,像上面的data参数静态语言能直接读出里面的属性 x, y,但是动态语言参数 data 显然不能直接读出里面包含什么属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// TS
function tsFunc (data: {x: number, y: number}) {
console.log('demo ts')
return Math.sqrt(data.x ** 2 + data.y ** 2)
}

// tsFunc() // 没有传入参数,这里的代码 vscode 会提示错误,这就是静态语言在编写代码的时候就可以知道有错误。
tsFunc({x: 3, y: 4}) //需要将参数代码一起写入。

// 再比如传入参数的个数,ts 能直接检测,但是生成的 js 文件不能检测
function get(param) {
return param
}

get('hello')

get('hello', 1) // error: 应有 1 个参数,但获得 2 个

编写代码时静态语言能识别到可能使用到的属性等,但动态语言不一定能提示的正确。

1
2
3
4
5
6
7
8
9
// 静态类型和动态类型的差别,静态类型在编写代码时就可以发现错误像C++,Java等,动态类型的语言则需要代码运行时才可以知道错误,像JavaScript,python。
// js-code

function jsFunc (data) {
return Math.sqrt(x ** 2 + y ** 2)
}

jsFunc() // 没有传入参数,但这里的代码 vscode不会提示错误,但实际运行会发生报错。

二. 静态类型

静态类型

就像前面看到的那样静态类型可以是基础类型 number string null undefined symbol boolean void enum 还可以是对象类型 Object,Array, class, function,还可以是自定义类型 interface 或任何类型 any 等详情 typescript官网
  • 定义为相应类型后可以直接使用对应类型的方法或属性如 number,vscode 直接提示

如图

类型属性提示

. 基础类型 number string null undefined symbol boolean any void never。。。

  • number 类型
1
const num: number = 123
  • string 类型
1
const Name: string = 'LinYY'
  • boolean 类型
1
const boolean: Boolean = true
  • null 类型 。null 类型不可以赋值给 undefined 类型和 联合类型(后面介绍)
1
let n: null = null
  • undefined 类型
1
let u: undefined = undefined

undefined 类型。可以作用到可选类型,因为可选的类型默认会有一个undefined 类型

1
2
3
4
5
6
7
8
interface E {
b: number
c?: number
}

let e: E = {b: 12, c: 12}

e = {b: 23, c: undefined}
  • any 类型。已经定义变量的类型不能再修改,否则报错。
    注意 any 类型,any 类型定义后可以修改为其他的类型
1
2
3
4
5
6
7
8
// any 类型可以修改成其他任何类型,TS 不对 any 类型作类型检测
let not: any
not = 2
not = '2'
not = true

// 处理不确定的数组类型 any 比较合适。
let listArr: any[] = ['1', 2, true]
  • void 类型 和 any 类型相反,表示没有任何类型

void 类型 通常作用在函数中代表没有返回值,虽然也可以作为其他变量的类型,但只能赋值成 undefined。换一个方向想函数总是有返回值的,如果不是一个确定的值那么就是 undefined 值,所以 void 其实是属于 undefined 的,所以一个变量类型是 void 时,值只能 undefined 值。但是 不能将类型“void”分配给类型“undefined”详情看例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// void 空类型,一般用于函数,
function noReturn(): void {
console.log('no value return')
}

function fn(): void {
// Error
return 3;
}

function fn5(): void {
}
let un: undefined = fn5(); // Error 不能将类型“void”分配给类型“undefined”

let voidValue: void = undefined
let voidValue2: void = null // 不能将类型“null”分配给类型“void”
  • never 一个特殊类型。简单的说如果函数是一个永远不会执行完的函数,返回值就是 never 类型,像函数 errorFunc,abs。
1
2
3
4
5
6
7
8
9
10
11
// never 类型,不会执行结束的函数类型
function errorFunc(): never {
throw new Error()
console.log('never') // 抛出错误后 这段代码不打印。
}

function abs(): never {
while (true) {
}
console.log('never') // 上面的代码永远是true 这段代码不打印。
}
  • 对象类型 object type。object {},array [], class {}, function
1
2
3
4
5
6
7
8
9
10
11
12
13
let person: {
name: string,
age: number
} = {
name: 'LinYY',
age: 12
}

// 或 (不推荐写法)
let personB:{name: string} & {age: number} = {
name: 'LinYY',
age: 12
}
  • 数组类型 也是对象类型,下面声明number型数组只能写入数字来初始化,写入字符串将会报错。
1
2
3
4
5
6
const list: number[] = [12, 23, 34]

//等同于,下面的数组泛型,泛型是什么之后会讲,先留一个印象。
const listA: Array<number> = [1, 2, 3]

// const listB: number[] = ['12', 23, 34]
  • class类 类型
1
2
class Person {}
const LinYY: Person = new Person()
  • function 函数类型, 下面的函数类型要求返回值是 number 数字类型,写成其他类型如 string 会报错。
1
2
3
4
5
6
7
8
9
10
const getNumber: () => number = () => {
// return 'LinYY' 报错
return 123
}

// 要求返回值是string 字符类型
const getString: () => string = () => {
return 'LinYY'
// return 123
}
  • interface 自定义类型,也就是接口
1
2
3
4
5
6
7
8
9
interface Point {
x: number,
y: number
}

const point: Point = {
x: 2,
y: 4
}
  • 多类型。变量的类型可以有多个,比如可以是 number 或 string类型
1
2
3
4
5
6
7
8
// 变量的类型可以有多个,比如可以是numberstring类型。
let temp: number | string = 23
temp = '23'

type alias 类型别名,类型别名不是 TS 的基本数据类型,类型别名常用于提取公共类型,下面 interface 接口会详细介绍
type User = { name: string, age: number }
let male: User = {name: 'LinYY', age: 18}
let famale: User = {name: 'nana', age: 18}

小 tip

注释小技巧tip: 使用 /** */ 可以给类型添加更友好的提示

1
2
3
4
5
6
7
8
9
10
11
12
13
// 注释
/**

* this is good Per
*/
interface Per {
name: string
}

const p: Per ={
name: 'LinYY'
}

在 typescript 里面 name 是一个预留关键字,不能直接当变量来用

三.类型注解和类型推断

type annotation 类型注解

  • 直接声明的类型,告诉TS变量是什么类型。比如这里的 count 是 number 类型
1
2
3
// type annotation 类型注解。
let count: number
count = 23

type inference 类型推断

没有直接声明类型,TS 会尝试去分析变量类型,如这里的 countB,推断是 number 类型。(此处加图说明)
如图

1
let countB = 23
  • 但是声明的变量没有直接在一行赋值 TS 将默认变量为 any 类型,如这里的变量 countC,鼠标箭头移动到 countC 上方就可以看到类型。正确写法是加上类型注解。
1
2
let countC // any 类型
countC = 233

TS 并不能所有的类型都能推断出来,那么什么时候使用类型注解呢?具体情况需要具体分析

  • 一般简单的变量声明可以不写类型注解。如这里的 num1 num2 sum。TS 能直接判断。
  • 一般函数的参数需要类型注解,返回值可以不用写类型注解,TS 能自动判断
  • 已经有未确定的 any 类型,需要加类型注解,如 total 显示为 any,原因是类型 a b 不确定。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let num1 = 1
let num2 = 2
let sum = num1 + num2 // TS 推断出 sum 是 number 类型

let obj = {
name: 'LinYY',
age: 18
}

// obj.name = 23 // TS 推断出来的类型 同样不能再修改

// 需要类型注解
function getSum(a, b) {
return a + b
}

const total = getSum(2, 3)

引用文章

【林一一】2021一份热乎的万字 TypeScript 教程(含4.0)


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!