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
| function tsFunc (data: {x: number, y: number}) { console.log('demo ts') return Math.sqrt(data.x ** 2 + data.y ** 2) }
tsFunc({x: 3, y: 4})
function get(param) { return param }
get('hello')
get('hello', 1)
|
编写代码时静态语言能识别到可能使用到的属性等,但动态语言不一定能提示的正确。
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。。。
1
| const Name: string = 'LinYY'
|
1
| const boolean: Boolean = true
|
- 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
| let not: any not = 2 not = '2' not = true
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
| function noReturn(): void { console.log('no value return') }
function fn(): void { return 3; }
function fn5(): void { } let un: undefined = fn5();
let voidValue: void = undefined let voidValue2: void = null
|
- never 一个特殊类型。简单的说如果函数是一个永远不会执行完的函数,返回值就是 never 类型,像函数 errorFunc,abs。
1 2 3 4 5 6 7 8 9 10 11
| function errorFunc(): never { throw new Error() console.log('never') }
function abs(): never { while (true) { } console.log('never') }
|
- 对象类型 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]
|
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 }
|
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
| // 变量的类型可以有多个,比如可以是number或string类型。 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
|
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 类型。(此处加图说明)
- 但是声明的变量没有直接在一行赋值 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
let obj = { name: 'LinYY', age: 18 }
function getSum(a, b) { return a + b }
const total = getSum(2, 3)
|
引用文章
【林一一】2021一份热乎的万字 TypeScript 教程(含4.0)