手拉手带你掌握TS数据类型

概述

TS为什么会出现呢?Coderwhy老师说的一句话我非常赞同 – 任何新技术的出现都是为了解决原有技术的某个痛点。那TS的出现是为了解决什么呢?答案当然是为了解决JS的缺陷,我们知道JS有不少的缺陷,例如:

  • ES5以及之前的使用var关键字关于作用域的问题
  • 最初JS设计的数组类型并不是连续的内存空间
  • 直到今天JS也没有加入类型检测这一机制
    而TS的出现就是解决JS的这些痛点的。
    那什么是TS呢?我们来看一下 TypeScript在GitHub GitHub 和 官方上对自己的定义:
  • GitHub 说法: TypeScript is a superset of JavaScript that compiles to clean TypeScript output
  • TypeScript 官网: TypeScript is a typed superset of JavaScript that compiles to plain JavaScript
    翻译一下: TypeScript 是拥有类型的JavaScript 超集 ,它可以编译成普通、干净、完整的JavaScript 代码

怎么理解上面的话呢?

  • 我们可以将TypeScript 理解成加强版的JavaScript
  • JavaScript 所拥有的特性,TypeScript 全部都是支持的 ,并且它紧随ECMAScript 的标准,所以 ES6 、ES7 、ES8等新语法标准,它都是支持的
  • TypeScript 在实现新特性的同时总是保持和 ES 标准的同步甚至是领先
  • 并且在语言层面上, 不仅增加了类型约束,而且包括一些语法的扩展比如枚举( Enum )、元组类型( TupleTuple )等 ;
  • 并且TypeScript 最终会被编译成JavaScript代码 ,所以你并不需要担心它的兼容性问题在编译时也可以借助于 Babel这样的工具

所以,我们可把TypeScript 理解成更加强大的JavaScript ,不仅让JavaScript更加安全,而且给他带来了诸多的好用特性。
这里有一张图可以更加直观的带你理解JS和TS的关系
在这里插入图片描述

TS数据类型

接下来进入到本篇文章的正题,这部分将从两方面着手讲述:

  1. TS和JS共有的数据类型
  2. TS独有的数据类型

需要说明一点的就是TS中声明的数据类型要注意大小写的区别。 例如,你想要定义一个数字类型的变量: 要写成 let num: number = 3不是 let num: Number = 3;虽然第二种写法从语法上来说也没有问题,但是Number并不是TS的基本数据类型,他是数字类型的包装类,而诸如 ‘number’ ,‘object’, ‘boolean’, ‘string’ 等才是TS的基本数据类型。
接下来就分别来讲述吧

TS和JS共有的数据类型

说明: 单独的 export {} 并不需要导出任何东西,但它会告诉TS编译器这个文件是一个模块,不是一个全局文件从而,在另一个文件中定义相同的变量不会产生命名冲突

number
let num: number = 3
console.log(num)

export {}
boolean
let bool: boolean = true
console.log(bool)

export {}
string
let str: string= 'string'
console.log(str)

export {}
Array

TS中数组定义有两种方式,一种是常规写法,另一种是泛型写法

// 常规写法
let arr1: string[] = ['a', 'b']
// 泛型写法
let arr2: Array<number> = [1,3,2]

export {}
Object

这个例子用到了类型声明type,具体可以看我的另一篇文章

type InfoType = {
  name: 'string',
  age: number
}

let info: InfoType = {
  name: 'Machigen',
  age: 21
}

export {}

object类型可以用来描述一个对象:

const info: object = {
	name: 'wanger',
	age: 21
}

// 下面的代码有问题
info['name'] = 'Q'
console.log(info.age)

export {}

但是这种定义方式导致定义的对象为空对象类型,所以,不能获取数据,也不能设置数据。 例如,上面的代码会报错。
在这里插入图片描述

Symbol

可以通过 symbol来定义相同的名称,因为Symbol函数返回的是不同值:

const s1: symbol = Symbol('name')
const s2: symbol = Symbol('name')

const person = {
  [s1]: 'Lee',
  [s2]: 'Jay'
}

export {}
null 和 undefined

在TS中,这两个类型和值等同

let n: null = null
let un: undefined = undefined

export {}
函数
function foo(num: number): string {
  return 'I am number ' + num
}
foo(3)

// 匿名函数不建议指定类型
const names: string[] = ['Lee', 'Kobe']
names.forEach((item, index, arr) => {
  console.log(item, index, arr)
})

export {}

匿名函数不建议指定类型 , 如上例,TS会根据forEach函数的类型推断出item,index和arr的类型这个过程称之为上下文类型,因为函数的上下文可以帮助确定参数和返回值的类型。

对象类型
type PointType = {
	x: number,
	y: number
}

function getCoordinate(point: PointType) {
	console.log('坐标是:(' + point.x + ',' + point.y + ')')
}
getCoordinate({ x: 2, y: 1})

export {}
可选类型

对象类型也可以指定哪些类型是可选的,可以在属性的后面加一个?:

type PointType = {
	x: number,
	y: number,
	z?: number
}

function getCoordinate(point: PointType) {
	console.log('坐标是:(' + point.x + ',' + point.y + ')')
	if(point.z)
		console.log('z轴是:', point.z)
}
getCoordinate({ x: 2, y: 1})
getCoordinate({ x: 2, y: 1, z: 3})

export {}

TS独有的数据类型

any

使用any类型,也就间接的把TS当成JS来用了

let a: any = 123
a = 'str'
a = {}

export {}
unknown

unknown 是TypeScript中比较特殊的一种类型,它用于描述不确定的变量。和any 类型有点似,但是 unknown 类型的值上做任何事情都是不合法的,必须进行类型缩小才能进一步操作

function foo(): string {
  return 'foo'
}

function bar(): number {
  return 123
}

const flag = true
const result: unknown;
if(flag) {
  result = foo()
} else {
  result = bar()
}

// unknown类型默认情况下在上面进行任意的操作都是非法的
// 要求必须进行类型的校验(缩小)
// 才能根据缩小之后的类型, 进行对应的操作
if (typeof result === "string") { // 类型缩小
  console.log(result.length, result.split(" "))
}

// 直接输出下面的代码会报错
console.log(result.length, result.split(" "))

export {}
void
// 1.在TS中如果一个函数没有任何的返回值, 那么返回值的类型就是void类型
// 2.如果返回值是void类型,
// 那么我们也可以返回undefined(TS编译器允许这样做而已)
function sum(num1: number, num2: number): void {
  console.log(num1 + num2)

  // return 123 错误的做法
}


// 应用场景: 用来指定函数类型的返回值是void
type LyricInfoType = { time: number, text: string }
// parseLyric函数的数据类型: (lyric: string) => LyricInfoType[]
function parseLyric(lyric: string): LyricInfoType[] {
  const lyricInfos: LyricInfoType[] = []
  // 解析
  return lyricInfos
}

// parseLyric => 函数/对象
type FooType = () => void
const foo: FooType = () => {}
 
// 1.定义要求传入的函数的类型
type ExecFnType = (...args: any[]) => void

// 2.定义一个函数, 并且接收的参数也是一个函数
// 而且这个函数的类型必须是ExecFnType
function delayExecFn(fn: ExecFnType) {
  setTimeout(() => {
    fn("why", 18)
  }, 1000);
}

// 3.执行上面函数, 并且传入一个匿名函数
delayExecFn((name, age) => {
  console.log(name, age)
})

export {}
never

never 表示永远不会发生值的类型。比如一个函数:

  • 如果一个函数中是死循环或者抛出异常,那么这会返回东西吗?
  • 不会,那么写 void 类型或者其他作为返回值都不合适, 我们就可以使用 never类型

可能有些抽象,我们一起来看个应用案例吧,其中用到了联合类型,具体可以看我的另一篇文章

// 一. 实际开发中只有进行类型推导时, 可能会自动推导出来是never类型
// 但是很少使用它
// 1.一个函数是死循环
// function foo(): never {
//   // while(true) {
//   //   console.log("-----")
//   // }
//   throw new Error("1233")
// }
// foo()

// 2.返回一个空数组的函数
// bar函数的类型为:never[]
function bar() {
  return []
}


// 二. 封装框架/工具库的时候可以使用一下never
// 其他时候在扩展工具的时候, 对于一些没有处理的case, 可以直接报错
function handleMessage(message: string | number | boolean) {
  switch (typeof message) {
    case "string":
      console.log(message.length)
      break
    case "number":
      console.log(message)
      break
//    case "boolean":
//      console.log(Number(message))
//      break
    default:
      const check: never = message
  }
}

handleMessage("aaaa")
handleMessage(1234)

// 此时switch分支的default会报错,必须加上'boolean'的判断情况才行
handleMessage(true)

export {}

在这里插入图片描述

tuple
// 保存个人信息: kobe 18 1.88
// 1.使用数组类型
// 不合适: 数组中最好存放相同的数据类型, 获取值之后不能明确的知道对应的数据类型
const info1: any[] = ["kobe", 18, 1.88]
const value = info1[2]
console.log()


// 2.使用对象类型(最多)
const info2 = {
  name: "why",
  age: 18,
  height: 1.88
}

// 3.使用元组类型
// 元组数据结构中可以存放不同的数据类型, 取出来的item也是有明确的类型
const info3: [string, number, number] = ["why", 18, 1.88]
const value2 = info3[2]


// 在函数中使用元组类型是最多的(函数的返回值)
function useState(initialState: number): [number, (newValue: number) => void] {
  let stateValue = initialState
  function setValue(newValue: number) {
    stateValue = newValue
  }

  return [stateValue, setValue]
}

const [count, setCount] = useState(10)
console.log(count)
setCount(100)

export {}

可以看出,元组与数组有些类似,那么tuple和数组有什么区别呢?

  • 首先, 数组中通常建议存放相同类型的元素不同类型的元素不推荐放在数组中 。(可以放在对象或者元组中) 。
  • 其次, 元组中每个素都有自己特性的类型 ,根据索引值获取到的值可以确定对应的类型
const info: (string|number)[] = ['coder', 25, 1.88]
const item1 = info[0] // 不能确定具体的类型,只能确定为联合类型

const tupleInfo: [string, number, number] = ['coder', 25, 1.88]
const item2 = info[0] // 类型一定是string

export {}

总结

本篇文章我们讲述了TS的基本数据类型及其简单使用,下篇文章我们一起来唠唠TS语法细节哪些事。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值