ts

121 阅读7分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第27天,点击查看活动详情

简介

TS是是由微软2012年开发的一款开源的编程语言

TypeScript 是 Javascript 的超集,遵循最新的 ES6、Es5 规范

TypeScript只是在JavaScript的基础上,添加了类型系统,并对JavaScript的语法进行了扩展,所以TS可以直接运行JS脚本

TypeScript遵循当前以及未来出现的ECMAScript规范,

但是TypeScript自身并不能被浏览器所识别,需要编译为原生的JavaScript后才可以被浏览器所识别

TypeScript倡导尽可能早的发现错误,所以TS可以在编译时就通过类型系统给予代码提示和类型检测

让我们可以在编译时就尽可能早的发现那些可能会出错的代码,而不是像JavaScript一样,必须要等到运行时才能发现对应的错误

image.png

JavaScriptTypeScript
动态语言具有静态语言的特点
运行时报错编译时报错
弱类型语言,没有类型强类型语言,需要在定义时指明类型
不支持模块、接口、泛型支持模块、接口、泛型
基本数据类型和引用数据类型更多的基本数据类型和引用数据类型,如any, never, enum等
在浏览器中直接运行编译为原生JavaScript后才能在浏览器中运行
# 安装 
pnpm add typescript

# 生成ts配置文件 - tsc是typescript安装后 生成的命令行工具(typescript compiler)
tsc --init

类型

类型说明示例
number整数和浮点数
支持二进制,八进制,十进制和十六进制数
let num: number
boolean布尔类型值
只有两个值: true 和 false
let bool: boolean
string字符串类型值
支持单引号,双引号和反引号
let name: string
数组一组变量的集合
定义方式:
1. type[]
2. Array<type>
let names: string[]
let scores: Array
元组1. 用来表示已知元素数量和类型的数组
2. 元组是一种特殊的数组,是TS对原生JS的扩展
3. 各元素的类型不必相同,对应位置的类型和长度需要相同
格式: [type, type, ...]
let tuple: [string, number, boolean]
anyany表示任意类型,使用any可以选择性的包含或移除类型检查
这在我们将js代码逐步改写为ts代码的时候,是十分有用的
过度使用any,会导致ts的类型检测功能的丧失
所以不推荐频繁使用any
let baz: any
unknownunknown是类型安全的any,对unknown做任何事情都是不合法的
除非通过类型断言或类型缩小将unknown转换为更为具体的类型
当我们不清楚某个值的具体类型或值的类型会随时发生改变的时候
我们可以将对应的值的类型定义为unknown
let uk: unknown
voidvoid表示没有任何类型,是一个和any完全相反的类型
当一个函数没有返回值时,可以设置函数的返回值类型为void
因为函数的默认返回值为undefined,所以undefined是void的子类型
在关闭strictNullChecks后,null也将成为void类型的子类型
function foo(): void {}
never那些永不存在的值的类型let nv: never
null用于表示空值
在关闭strictNullChecks的时候,null是任意类型的子类型
let baz: null
undefined用于表示未赋值的变量
在关闭strictNullChecks的时候,undefined是任意类型的子类型
let bar: undefined

联合类型和交叉类型

// typeA | typeB --- 联合类型 --- 表示的是或的概念,即该类型即可以是typeA,也可以是typeB
// typeA & typeB --- 交叉类型 --- 表示的是且的概念,即该类型必须同时符合typeA和typeB的要求
let arr1 = number | string[] // arr1 的类型为数值类型 或 字符串数组类型
let arr2 = (number | string)[] // arr2 的类型为 字符串或数值 组成的 数组类型

// 默认情况下,ts会认为当前文件是一个普通的JS文件,所以其变量会被认为是全局变量
// 因此在多个js文件中定义同名变量的时候 会出现错误提示
// 使用export {} 让当前js文件具有模块作用域
export default {}

unknown

// 1. 任何类型都可以赋值给unknown类型
let un:unknown
un = 1.88
un = true
un = 'Klaus'
// 2. 不能将unknown类型赋值给其它类型 或 对unknown类型进行任何操作
let un:unknown
let num = 18
num = un; // error
console.log(un.length) // error
// 3. unknown与其它任何类型组成的交叉类型最后都是其它类型
//    unknown除了与any以外, 与其它任何类型组成的联合类型最后都是unknown类型
let type1: unknown | number | string //  typeof type1 -> unknown
let type2: unknown | any // typeof type2 -> any
let type3: unknown & number // typeof type3 -> number

// 注意: unknown & any => any
let type4: unknown & any // typeof type4 -> any
// never类型是unknown类型的子类型
let type: never extends unknown ? true : false // true

never

never表示的是那些永不存在的值的类型

也就是那些总是会抛出异常或根本就不会有返回值的函数(如死循环函数)

一个变量也可以被设置为never类型,但是这么做往往没有什么实质性的意义

never是ts中最底层的类型,never类型是任何类型的子类型,也可以赋值给任何类型

然而,除了never本身之外,没有任何的类型是never的子类型或可以赋值给never类型(即使是any也不行)

// 会抛出异常的函数的返回值为never
function error(msg: string): never {
	throw new Error(msg)
}

error('error')

// 死循环的函数,不存在返回值
// 所以死循环函数的返回值是never
function infiniteFn(msg: string): never {
	while(true) {
		console.log(msg)
	}
}

object

object表示非原始类型,也就是除numberstringbooleansymbolnullundefined之外的类型

使用object类来约束对象的类型的时候,并没有办法有效的识别对象中的各个属性和方法

所以使用object来定义一个对象的时候,只能使用对象的公共属性和公共方法

因此在实际开发中,一般使用接口或类型别名来对一个对象的结构进行约束

枚举

enum类型是对JavaScript标准数据类型的一个补充

像C#等其它语言一样,使用枚举类型可以为一组数值赋予友好的名字

enum Gender{
  Male,
  Female
}

/*
	上述代码会被编译为

	"use strict";
	var Gender;
	(function (Gender) {
			Gender[Gender["Male"] = 0] = "Male";
			Gender[Gender["Female"] = 1] = "Female";
	})(Gender || (Gender = {}));


	1. 枚举默认是数值枚举,默认索引值是从0开始,依次向上递增的
	2. 可以通过枚举值获取对应的索引值,通过枚举值我们可以获取对应的别名
*/

console.log(Gender.Male) // => 0
console.log(Gender.Female) // => 1
console.log(Gender[0]) // => Male
console.log(Gender[1]) // => FeMale
// 枚举值的每一个索引都是可以自定义的
// 如果枚举值是数值类型的时候, 自定义枚举值后续的枚举会依次递增
enum Gender{
  Male = 10,
  Female
}

console.log(Gender.Male) // => 10
console.log(Gender.Female) // => 11
// 枚举值可以是字符串
// 但是字符串会导致后续的枚举值无法自动递增
// 所以如果自定义枚举值为字符串类型的时候
// 后续的枚举值需要依次全部都自定义
// 除非后续有一个枚举值的值又为了数值类型
// 那么其后续的枚举值才又可以实现依次递增的结果
enum Gender{
  Male = 10,
  Female = 'female'
}

console.log(Gender) // => female

bigInt 和 symbol

// 如果需要使用100n 这类语法 需要在tsconfig中设置target为ESNext
// 如果需要使用BigInt和Symbol这类内置函数,需要在tsconfig中的lib值中添加ESNext
// 之所以需要打开,是因为默认情况下,ts编译使用的是ES2015语法

// bigInt类型值是bigInt
let big1: bigint = BigInt(100) 
let big2: bigint = 300n

// symbol类型值的类型为symbol
let sym: symbol= Symbol()

类型断言

类型断言可以用来手动指定一个值的类型,即允许变量从一种类型更改为另一种类型

类型断言可以让我们手动指定对应变量的类型

// 类型断言有两种方式
// 一, 值 as 类型
let num = foo as number

// 二, <类型>值
let num = <number>foo

类型别名

类型别名就是使用type关键字给一个类型起个新名字, 但是它们都代表同一个类型,并不是新建了一个新的类型

type type1 = number | string
type type2 = (num1: number, num2: number) => number
type type3 = {
	name: string,
	age: number
}

接口

接口通过interface关键字为对象或函数这类复杂类型定义结构

interface IUser {
  firstname: string,
  lastname: string
}