# 数据类型

ts基础数据类型需要类型校验,都必须为每种数据指定类型。

# 布尔类型

let a:boolean = true
console.log(a)

# 数字类型

let num1:number = 1;
let num2:number = 1.2;
console.log(num1+num2);

# 字符串

let str:string = "hello world"
let str2: string = `calc num ${num2} hhhh`
console.log(str2);

# 数组

// 数字数字
let arr1:number[] = [2, 2, 1, 44, 5]
let arr4:Array<number> = [2, 2, 1, 44, 5]
// 字符串数组
let arr2:string[] = ['sts', 'chagn', 'world']
let arr3:Array<string> = ['sts', 'chagn', 'world']

let arr5:boolean=[true, false]

// 二维数组

let arr6:number[][] = [[1], [2], [3]]

# 元组类型(tuple)

属于数组的一种,可以定义多种类型的值

let tuple:[number, string, boolean] = [2222, 'hello', true]
tuple.push(1) // push时为联合类型,只能push number, string, boolean这三种类型

// 数组只读
let tuple: readonly [number, string, boolean] = [2222, 'hello', true]

// 可选元素,使用别名
let arr: [x: boolean, y?: number] = [true]

// 或者any类型比元祖类型更简单
let arr5:any = [1, 'xxx', true, 2]
console.log(tuple)

# Set和Map

let set:Set<number> = new Set([1, 2, 3, 3, 4, 5])
// Set<T> T为Set数组的类型

let map:Map<number, any> = new Map()
// Map<K, V> K表示Map的键为什么类型,V表示value值为什么类型
map.set(1, 'xxx')
map.set(2, 1)

# 枚举类型enum

下一章节枚举类型

# Any类型

任何类型,可以任意赋值

let notSure:any = 4
    notSure = 'hello'
console.log(notSure) // hello

let DBox:any = document.getElementById('box')
DBox.style.color = 'red'

# unknown

不知道是什么类型

和any类型类似,可以是任意类型,但是它不可以赋值给其他类型,只能赋值给自身,或者any。

无法读取任何属性和方法,如赋值为对象,不能调用里面的属性。

let a:unknown = 1
let b:number = 1
let c:any = 2
b = a // 这样会报错
c = a // 可以

# null和undefined

// num 可能是number或者是undefined
let num:number | undefined;
// num = 122
console.log(num)

# void类型

一个方法没有任何返回值,一般用于函数返回值后面

// 没返回值
function run():void {
  console.log(111)
}
run();

// 有返回值
function run1():number {
  console.log(111)
  return 1111
}
run1();

# Never类型

never类型表示的是那些永不存在的值的类型。如抛出异常或者死循环的函数,没有返回值。

function error(message: string): never {
  throw new Error(message);
}

# object类型

表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。

object表示引用类型,Object和{}都表示顶层对象。

# symbol类型

symbol类型表示定义一个唯一的值,主要用来解决对象中属性名冲突,不能定义两个相同的明年名字的问题。

let sym2 = Symbol('key');
let sym3 = Symbol('key');
console.log(sym2 === sym3) // false

// 让两个symbol相等
// for去找有没有注册过symbol的可以,有会直接用,不会创建新的symbol
console.log(Symbol.for(1) === Symbol.for(1)) // true

// 对象的属性
let sym = Symbol(1);
let sym2 = Symbol(1);
let obj = {
  name: 'aaa',
  [sym]: 'xxx'
}
obj[sym2] = 'xxx'
console.log(obj[sym]); // xxx

// 获取对象所有属性
Reflect.ownKeys(obj) // ['name', Symbol(1), Symbol(1)]

# 类型断言

一个任意类型的数据,你清楚的知道它是什么类型,然后把它当做某个类型来调用它和它的属性或方法。

型断言有两种形式。 其一是“尖括号”语法:

let someValue1:any = "this is a string";
let strLength1:number = (<string>someValue1).length; // 把any类型当做string类型来获取它的length属性

另一个为as语法:

let someValue2: any = "this is a string";
let strLength2: number = (someValue2 as string).length;
interface A {
  name:string
}
interface B {
  size:string
}

// a的参数可以是A或者B,但是如果直接使用A或B中的属性,它不确定是哪个是找不到的
let a = (type: A | B):void => {
  // console.log(type.name) 无法访问
  console.log((type as A).name) // 断言为A
}

// window挂在属性
// window.abc = 123 无法找到
(window as any).abc = 123

# 联合类型

当一个变量或者参数需要支持多种类型时。

// 变量
let a: number | string = 'abc'

// 函数
function fn(type: number | boolean):boolean {
  return !!type
}

# 交叉类型

同时需要满足多个类型。

interface Animal {
  name:string
}
interface Dog {
  size:string
}

function xiaogou(obj: Animal & Dog):void {
  console.log(obj)
}
xiaogou({name: 'xiaohei', size: 'small'})

# 内置对象

  • ecma内置对象如Date、Number、RegExp、Error、XMLHttpRequest等
  • BOM和DOM的内置对象
// ecma内置对象类型为自己本身
let num:Number = new Number(1)
let date:Date = new Date()
let reg:RegExp = new RegExp(/\w/)
let err:Errow = new Errow('报错了')
let xhr:XMLHttpRequest = new XMLHttpRequest()

// 获取dom元素

// 常见的类型为 HTML(元素吗)Element
// 或者都可归类为 HTMLElement Element
let div:HTMLDivElement = document.querySelector('div')
let div:HTMLInputElement = document.querySelector('input')
let div:HTMLElement = document.querySelector('footer')
let div:Element = document.querySelector('footer')

// 元素集合 NodeList可以遍历
let div:NodeList = document.querySelectorAll('div')
// 动态获取
let div:NodeListOf<HTMLDivElement | HTMLInputElement> = document.querySelectorAll('div/input')

// 浏览器内置对象
let storage:Storage = localStorage
let lo:Location = location
let promise:Promise<number> = new Promise((resolve) => {
  resolve(1)
})
promise.then(res => {
  console.log(res)
})

let cookie:string = document.cookie

# 类型推论

定义一个变量,给定一个已知的初始值,ts会自动推论出这个变量的类型的,可以不用进行类型注解的,后面都会以这个类型进行验证。

如果定义变量,没有给初始值并且也没标注类型,ts会默认推论为any类型。

let a = 'xxx' // let a: string
let b // let b: any

# 类型层级

  • 1、any、unknown 顶级类型
  • 2、Object 顶层对象
  • 3、String、Number、Boolean、Array 内置对象
  • 4、string、number 基础类型
  • 5、'abc'、1、true 类型值
  • 6、never

# 类型别名

使用type关键字定义类型别名,其作用就是给类型起一个新名字,可以作用于原始值(基本类型),联合类型,元组以及其它任何你需要手写的类型。

type 和 接口 类似,可以约束一个对象或者函数的类型,但是没有继承和同名合并,不可多次定义。进行类型约束最好用接口。

// 定义别名
type n = number
let num: n = 123;

// 联合类型
type Second = number | string;
let time: Second = 10;
let time: Second = '10';

// 交叉类型
type and = number & string;
// and 推断为 never类型

// 对象类型
type User = {
  name: string
  age: number
}
let obj: User = {
  name: 'xxx',
  age: 19
}

// 作为注解,限制类型的值
type A = 'A' | 'B' | 'C' | 1 | 2
function fn(value: A):void {
  console.log(value)
}


// 高级用法
// extends包含的意思,左边的值会不会作为右边的子类型
type num = 1 extends number ? 1 : 0
console.log(num) // 1

type num = 1 extends never ? 1 : 0
console.log(num) // 0 never层级最低