ts概述、ts环境准备和编译、ts类型声明


1. ts概述

TypeScript 由微软开发的自由和开源的编程语言,它可以在任何任何操作系统上运行。可以理为TypeScript是JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。

在这里插入图片描述

Ts和Js最大的不同,在于Ts有类型检查。在一些大型项目,多人合作开发的项目中,类型的统一是一件非常困难的事件,有了Ts的加持,可以方便类型的统一。

TS浏览器或一个js运行环境是不支持,需要把ts转为js,才能运行。

在这里插入图片描述

一般的人少开发的项目,不要用,用它反而降低开发速度,但是如果多人开发,或项目有可能变大,建议还是一步到位,用上ts。

2. ts环境准备和编译

ts不能直接运行,需要把ts转成js来运行,需要ts编译器 typescript 最新版本为4.x,需要全局安装一 typescript 编译器:npm i -g typescript

检查一下,是否安装成功tsc --version,如果能看到版本号,则表示安装成功。

将 ts 文件转换为 js 文件命令:

// 转换  tsc xx.ts 就可以了  -w 只能此ts文件有修改它会自动编译 --outDir 指定编译后的js放到哪里去

// tsc src\1.ts --outDir dist -w

进入到 dist 目录下,运行文件:node 1.js

3. ts类型声明

TypeScript支持与JavaScript几乎相同的数据类型,此外还提供了自己特有的一些类型。

  • 类型声明(手动给变量或参数指定类型)

    类型声明是TS非常重要的一个特点,通过类型声明可以指定TS中变量(参数、形参)的类型,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错,类型声明给变量设置了类型,使得变量只能存储某种类型的值。

  • 自动类型(类型推论[ts很重要的一个特性])

    当对变量的声明和赋值是同时进行的,TS编译器会自动根据右边的值来给左边的变量赋对应的类型。从右决定左类型【场景最多】

注意:

  1. ts中默认提供的内置类型,在指定时一定要全小写,例如:

    string

    number

    boolean

    object

    null

    undefined

    any

    unknown

  2. 自定义类型时,可能是大写

3.1 布尔值

// 手动类型声明
// 声明一个变量,指定它的类型为boolean,此时,此变量只能赋值布尔类型的值
let arg:boolean
arg = true

// 自动类型声明
// 右侧决定左侧类型  直接给变量赋值,ts编译器会在编译时,根据右侧的值类型来赋值给左侧变量类型
// 工作中用的多,如,给一个默认值同时就给当前的这个参数一个类型
let arg1 = true

3.2 数字类型

// 先声明类型 ,再赋值
let arg:number
arg=1

// 自动类型赋值
let arg1 = 2

也可以复制其他进制的数字类型:

  • let decLiteral: number = 6; // 十进制
  • let hexLiteral: number = 0xf00d; // 十六进制
  • let binaryLiteral: number = 0b1010; // 二进制
  • let octalLiteral: number = 0o744; // 八进制

3.3 字符串类型

// 先声明类型 ,再赋值
let arg: string
arg = 'hello'

// 自动类型赋值
let arg1 = 'hello'

3.4 any和unknown

any和unknown,它俩都表示任意类型,unknown 是 ts3.x 后提供的,而 any 一开始就有。

两者区别:

我们可以对any类型进行任何操作,ts不需要进行检查类型,赋值的类型对于ts编译器来说就不重要了,相当于在ts中写js,所以少用,类型不安全。

unknown是any的安全类型,unknown只能被赋值unknown本身,unknown本身赋值是随意的,但是在调用的时候,会进行类型检查 ,所以需要类型断言,才能用。unknown一般会它来完成类型的转换工作:string类型 => unknown => number类型。

// === any 任意类型
let arg1: any
arg1 = 1
arg1 = 'zhangsan'
arg1 = true
// arg1它是一个any,调用它的print方法
arg1.print()
arg1.length

// === unknown 任意类型
let arg2: unknown
arg2 = 1
arg2 = 'zhangsan'
arg2 = true
// 在any中是可以,ts不检查,js通过,但是unknown用时类型的检查,看一下当前类型中有没有此方法或属性 没有print报错
// arg2是一个unknown,未知类型,不知道现在有没有print方法,不知道就报错,unknown比any要安全的地方
// 报错
// arg2.print()
// arg2.length

3.5 void、null、undefined

void:

它表示没有任何类型, 声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined,一般多用于函数返回值指定。

undefined和null:

两者各自有自己的类型分别叫做undefined和null。 和 void 相似,它们的本身的类型用处不是很大。

// void 一般用于【函数返回值类型中指定】,表示当前的函数没有返回值,也可以用来指定变量,表示此变量为undefined
// null类型/undefined
// void类型 了解知道它还可以赋值给变量
let arg1: void
arg1 = undefined

// 此函数没有返回值,如果你不指定函数的返回值,ts会根据当前函数的结果来推断出它的返回值
// 在工作中,一般函数非必要的情况下,一般不指定返回值类型,让它自动推断出来
// 没有返回值的几种情况:
function print(): void {
    
    
  console.log(123)
}

function print(): void {
    
    }

function print(): void {
    
    
  return
}
function print(): void {
    
    
  return undefined
}

// null类型
// 如果要把一个变量声明为null类型
let arg2: null
arg2 = null

// undefined类型
let arg3: undefined
arg3 = undefined

3.6 never类型

never类型表示的是哪些永不存在的值的类型,此类型多用于ts的底层实现中使用,在应用层级中,一般用不到。

在底层中的用法类似这样:type EType = xx extends yy ? string : never

// 类型保护 typeof得到类型  instanceof是不是它的实例
function print(name: string) {
    
    
  if (typeof name === 'string') {
    
    
    console.log(name.length, '字符串')
  } else {
    
    
    // ts中,此句,写和不写没有区别,不会执行到这里  never在底层,表示
    console.log(name)
  }
}
// 这样写在ts编译时会报错,不通过
// print(123)

never类型是unknown类型的子类型:

// never类型它是unknown类型的子类型
// extends在ts中理解为,never定义的属性或方法在 unknown全部都要有,则为真
// extends判断一个类型是否是别的类型的子类型
type NeverType = never extends unknown ? string : boolean
let a: NeverType
a = '1'

3.7 字面量类型

声明一个变量,变量的值,它只能在规定的几个值范围中去选择其中之一来赋值。

// 类型定义在变量的后面用冒号,然后紧跟定义的类型
// 字面量类型无法进行类型模块化,如果想要进行模块化,可以使用枚举类型
let arg: 'aa' | 1 | true
arg = 1

3.8 枚举类型

指定的范围中去选择值。定义一个枚举类型,可以指定的元素的值,也可以不指定,如果不指定,默认值为数字,值从0开始,累加下去。

枚举类型可以通过 export 进行模块化导出。

定义一个枚举类型,不指定元素的值:

// 可以把枚举,定义为数组
enum Color {
    
    
  // 0
  red,
  // 1
  green,
  // 2
  blue,
  // 3
  pink,
  // 4
  yellow
}
// 如果指定的一个变量它的类型为枚举类型,则在赋值时,最好是使用 枚举类型.元素 进行赋值
let c: Color
c = Color.green
console.log(c); // 1

// 类型转换出来的都为数字,所以在给变量赋值为数字时,不会报错,类型对的,可以成功运行
c = 10
console.log(c); // 10

定义一个枚举类型,指定元素的值:

enum Color {
    
    
  red = 'red',
  green = 'green'
}
let c: Color
c = Color.green
console.log(c) // green

定义一个枚举类型,一部分指定值,一部分不指定值:

// 如果你指定值,它的类型为数字,则下面的元素会从上一个元素的数字+1开始,下一个元素无需手动指定
// 如果你赋值是非数字,则下一个元素需要手动给值,直到遇到上一个元素值为数字为止
enum Color {
    
    
  // 0
  red,
  // green
  green = 'green',
  // 10
  blue = 10,
  // 11
  pink,
  // 12
  yellow
}
let c: Color
c = Color.pink
console.log(c) // 11

枚举类型小案例:

// redux   action
enum ActionEnumType {
    
    
  addNum = 'addNum',
  decrNum = 'decrNum'
}
const reducer = (state = {
    
     num: 1 }, action: {
    
     type: ActionEnumType; payload: any }) => {
    
    
  return state
}
// 使用了枚举类型 ,把原来的type给限定义范围,只能在规定的规范中去使用值
reducer({
    
     num: 100 }, {
    
     type: ActionEnumType.addNum, payload: [] })

3.9 object对象类型

使用 object 规定对象类型:

在工作中,一般不要轻易给一个参数或变量一个object类型,它虽然会有类型检查,但是它的范围有点的广,比如下面这个例子,我的目的是定义一个{id:1}的对象,但是当赋值为[]时,类型检查也会通过。

// 在工作中,一般不要轻易给一个参数或变量一个object类型,它虽然会有类型检查,但是它的范围有点的广
let arg: object
arg = []
arg = {
    
     id: 1 }

使用{属性:类型,属性:类型}方式规定对象类型:

let arg: {
    
     id: number; name: string }
arg = {
    
     id: 1, name: '张三' }

定义可选属性:

// 对象中的属性,有一些属性它是可以定义,也可以不定义 可选属性 用?
// ?: 可选属性,在赋值时,可以定义此属性,也可以不定义,不会报错
let arg: {
    
     id: number; name: string; age?: number }
arg = {
    
     id: 1, name: 'aaa', age: 10 }
arg = {
    
     id: 1, name: 'aaa' }

定义动态属性:

// 没有事前定义的属性,它的名称是不确定,数据类型不确定,现在需要obj对象它可以定义此新添加属性
// key的名称我不知道,但是类型我是确定的,string  key它就是变量
// value值,类型不确定,因为它什么可能都会存在所以规定为any类型
// let arg = {id:1,name:'aaa'}
// arg['sex'] = '0'
// arg['a'] = 1
// arg['b'] = true
// console.log(arg)

// 动态属性,可能还存在多个
let arg: {
    
     id: number; name: string; [key: string]: any }
arg = {
    
     id: 1, name: 'aaa' }
arg['sex'] = '0'
arg['a'] = 1
arg['b'] = true
arg['aa'] = []
console.log(arg) // { id: 1, name: 'aaa', sex: '0', a: 1, b: true, aa: [] }

对象兼容性:

// 对象的兼容性  --- 【一个类型是另一个类型的子集/范围广的赋值给范围少的】 如果你想把一个类型赋值给另一个类型,
// 则前提是,你当前类型中所有的属性在接受变量类型中都有
// 接受者是赋值者的超集就可以
let arg1: {
    
     id: number; name: string; age: number }
let arg2: {
    
     id: number; name: string }
let arg3: {
    
     id: number }
arg1 = {
    
     id: 1, name: '张三', age: 7 }
arg2 = {
    
     id: 1, name: '张三' }
arg3 = {
    
     id: 1 }
// arg2赋值给arg1,不行,会报错
// arg1 = arg2
// arg1赋值给arg2,可行,不会报错
arg2 = arg1
// 不会报错
arg3 = arg2

3.10 数组

// 如果直接赋值一个空数组,推导出来的为一个any[]
let arg = []

// 如果赋值一个数字类型的数组,推导出来的为一个 number[]
// number[]
let arg1 = [1, 2]

// 规定数组类型方式1:
// 定义一个指定类型的数组   指定类型,没有指定长度,它称为数组
let arg2: number[] = [1, 2, 3]

// 规定数组类型方式2:
// Array<类型> 泛型 定义指定类型的数组
let arg3: Array<string> = ['a', 'b']

3.11 元组

let arg: [number, string]
arg = [1, 'a']

// 注意:元组只能是定义出来的,推导出来的,都为数组,比如下面这种写法,表示一个数组
let arg2 = [1, 'a']

3.12 自定义类型type

自定义类型给变量用:

// 通过type关键字完成自定义类型的定义  type定义的类型,在同一个模块下面,名称是不能重名的
// 定义类型给变量用
type UserType = {
    
     id: number; name: string; age: number }
let arg1: UserType
let arg2: UserType
let arg3: UserType

自定义类型给函数用:

// 定义一个类型来限制函数的参数类型和返回的类型
// 定义的参数类型限制,它只限制类型,不限制你所定义的形参的名称
// 写法1:
// type FnType = { (a: string, b: number): string }
// 写法2:
type FnType = (a: string, b: number) => string
const fn: FnType = (id: string, name: number) => {
    
    
  return 'hello'
}

限制构造函数参数的类型:

// new (id: number) 限制构造函数参数的类型,表示当前一定它是一个类,可以被实例化,且能用new来实例,并且限制了它的构建函数参数类型
// 注意:自定义类型也可以进行模块化导出
export type PersonType = {
    
     new (id: number): void }

class Person {
    
    
  constructor(id: number) {
    
    }
}

let p: PersonType = Person

3.13 联合类型

多个类型可以选择的,类型和类型之间用|隔开

// ----------------------- 联合类型  多个类型可以选择的 类型和类型之间用 | 隔开
// 此变量可以赋值的类型可以是number,也可以是string,还可以是boolean
// let arg: number | string | boolean | string[]
// 联合类型中有unknown或any ,任何的类型和它俩联合都是转为 unknown或any
// let arg: string | unknown // unknown
// let arg: string | any // any
// 联合类型中有 never 类型,它是不会生效,写和不写没有区别,相当于类型不存在,类型检查时也不会有
// number | string | boolean | string[],这个类型相当于下面这种写法
let arg: number | string | boolean | string[] | never

3.14 交叉类型

取两个类型的交集。

普通变量进行交叉:

type type1 = number | string
type type2 = string | boolean
// string
type type3 = type1 & type2

如果是对象类型,进行交叉,得到是一个并集操作:

type type1 = {
    
     id: number; name: string }
type type2 = {
    
     age: number }
// {id:number,name:string,age:number}
type type3 = type1 & type2
let t: type3 = {
    
     id: 1, name: 'aa', age: 1 }

注意:对象类型的交叉,最好保证属性名如果重名,则类型相同或是一个联合类型

如果对象类型中,遇到属性的名称和类型相同的情况,则会直接进行合并,例如下面的例子直接会把id:number合并为一个类型限制:

type type1 = {
    
     id: number; name: string }
type type2 = {
    
     id: number; age: number }
// {id:number,name:string,age:number}
type type3 = type1 & type2
let t: type3 = {
    
     id: 1, name: 'aa', age: 1 }

如果对象类型中,遇到属性的名称相同,但类型不相同的情况,则会把类型不同的属性限制为 never 类型:

type type1 = {
    
     id: number; name: string }
type type2 = {
    
     id: string; age: number } // 把 id 的类型变成 never 类型
// 注意:type type2 = { id: number|string; age: number } ,这种情况下,id 的类型为 number
// {id:never,name:string,age:number}
type type3 = type1 & type2
// let t: type3 = { id: 1, name: 'a', age: 20 } // 报错,id无法来赋值

使用交叉类型来扩展属性:

// 假设 Slice 对象是通过npm安装的一个reduxjs中的类型
type Slice = {
    
    
  name: string
}

// 通过交叉类型扩展属性
type ExtSlice = Slice & {
    
    
  username: string
}

const userSlice: ExtSlice = {
    
    
  name: 'aa',
  username: 'admin'
}

// 小案例,假设有下面这样的场景,我们可以通过交叉类型实现属性的扩展
import {
    
     Request, Response } from 'express'
const express = require('express')
const app = express()
app.listen(9000)

app.get('/api/users', (req: Request & {
    
     html: string }, res: Response) => {
    
    
  // html属性它是我们自定义提供 是开发者自己创建的
  req.html = 'abc'

  res.send('aaa')
})

3.15 类型断言

**断言:**断定某一个类型或值。有些情况下,变量的类型对于我们来说是很明确,但是TS编译器却并不清楚,此时,可以通过类型断言来告诉编译器变量的类型。

语法:[值 as 类型] 或 [<类>值]

类型断言:

假设现在有一个 arg 变量,它既可能是 number 类型也可能是 string 类型,当我们访问它的 length 属性时,就会报错,原因是,arg 如果为 number 类型的话,就没有 length 属性。想要解决这一问题,我们有两种方法:

  1. 类型保护

    function fn(arg: number | string) {
          
          
      // string类型上面是有length属性,但是number它没有,所以你直接用,它就会报错,number也是有可能的
      // 类型保护
      if (typeof arg === 'string') return arg.length
      return arg
    }
    
  2. 断言

    function fn(arg: number | string) {
          
          
      // string类型上面是有length属性,但是number它没有,所以你直接用,它就会报错,number也是有可能的
      // 断言它现在一定是一个string类型的变量
      // return (<string>arg).length
      return (arg as string).length
    }
    

值断言:

值断言指用符号!:表示当前变量一定会有值,不会为空。

class Person {
    
    
  // 属性暂时可能没有赋值,但是后续我一定会赋值给它,所以可以用一个断言  非空
  name!: string

  // 也可以在构造函数中赋值
  // constructor(name: string) {
    
    
  //   this.name = name
  // }
}

链判断符:

判断?.左侧对象是否为 null 或 undefined ,如果是就返回 undefined。

res?.data相当于:res == null ? undefined : res.data

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45605541/article/details/128470396
ts