ts之变量声明以及语法细节,ts小白初学ing

TypeScript

用js编写的项目虽然开发很快,但是维护是成本很高,而且js不报错啊啊啊啊啊!!!

以js为基础进行扩展的

给变量赋予了类型

语法、实战(ts+vue3)

TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准(ES6 教程)。

TypeScript 由微软开发的自由和开源的编程语言,在 JavaScript 的基础上增加了静态类型检查的超集。

TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器上。

转换为js一般用Babel?TSC,一般使用Babel比较多

特点:始于js,归于js,类型校验,适合开发大型项目,拥有js最新的特性

一、变量的声明

1、大致的格式

var/let/const 标识符 : 数据类型 = 赋值;
let message:string = "Hello World"

2、类型推导

let message= "Hello World"

会自动推导出类型

2、number

不区分整数、浮点数类型,统一都为number类型

3、Array类型

let arr  = ["abc" , "bdf" ,"scd"]
// 类型推导为string[]
let arr2 :string[] = ["asd","fgh","jkl"]
arr2.push("xcx")
// arr.push(123)
// 泛型的方式来约束
let arr3 : Array = [1,2,3,4,5]
arr3.push(6)

4、object类型

let o  : {
  name:string,
  age:number
} = {
    name:"abc",
    age:18
}

但是其实这样会不安全

let o   = {
    name:"abc",
    age:18
}

直接这样写就好啦

5、函数定义类型

const sum = ( num1:number ,  num2:number) => {
return num1 + num2
}
sum(1,2)

如果后面不写类型的话,得到的是any类型

函数的返回值类型是可以推导的,也可以通过以下方式进行定义

const sum = ( num1:number ,  num2:number) : number => {
return num1 + num2
}

6、匿名函数定义类型

// 匿名函数,最好不要添加对应的类型,一般根据上下文进行推导
const names : string[] =['a','b','c']
names.forEach((item , index , arr) => {
  console.log(item , index , arr)
})

7、对象

type PointType = {
  x : number,
  y : number
}
const printPoint = (point: PointType) => {
  console.log("x坐标",point.x)
  console.log("y坐标",point.y)
}
printPoint({x:1 , y:2})
export{}

8、可选类型

在属性后面加上一个问号

9、非常非常重要的类型 – any

let id : any = "aaa"   //推导出来id是一个string类型
// 但是id有可能使用数字表示的
id = 123    //用了any之后就可以用数字啦
id = {name : "why" , level : 90}
// 但是感觉和js大差不差了
// 可以搞一个联合类型 |
let id2 : string | number = "aaa"
id2 = 123

10、unknown类型

描述类型不确定的变量

在unknown类型上进行所有的操作都是不合法的

可以使用类型缩小来解决这个问题

let foo:unknown = 123
// foo.toString()   //会报错的
if (typeof foo === 'number'){
    foo.toString()  //类型断言
}

11、void 类型

表示函数没有返回值,它的返回值就是void类型

const sum = ():void => {
   console.log("sum");
}
sum()
export{}

可以将undefired配置反弹

12、 never类型

应用场地:

永远不会发生值的类型,比如死循环或者抛出异常

13、tuple类型

tuple,通常可以作为返回的值

可以存放多种数据类型,而且明确的知道是什么类型

const info :[string , number , number] = ['张三',120,11]

二、语法细节

1、联合类型和交叉类型

联合类型:就是用’|'来分隔已有的类型

交叉类型:满足多个条件,一般用于interface,&进行连接

// 交叉类型:同时满足多个类型
interface Fish {
  name : string
  age : number
}
interface Swim {
  sex : string 
}
// 交叉类型的使用
type p = Fish & Swim

2、type和interface

类型别名:type定义别名

  // type取别名
  type myNumber = number | string
  let id : myNumber = 123
  const printId = (id : myNumber) => {
    console.log(id)
  }

interface:

// 直接声明接口
interface PointType2 {
  x : number,
  y : number
}
const printPoint = (point : PointType2) => {
  console.log(point.x, point.y)

}

大部分情况下两个都是可以的

区别:

接口类型只能够声明对象

  type myNumber = number | string
  let id : myNumber = 123

在声明对象时,interface可以多次声明

// 直接声明接口
interface PointType2 {
  x : number ,
  y : number
}
interface PointType2 {
  x : number ,
  y : number,
  z : number
}
// 声明都必须要满足
const point : PointType2 = {
  x : 1,
  y : 2,
  z : 3
}
const printPoint = (point : PointType2) => {
  console.log(point.x, point.y)
}

支持继承

interface PointType3 extends PointType2{
  r : string
}

3、类型断言和非空断言

类型断言 as :通过类型断言就可以去将类型转换成具体的类型

const imgUrl = document.querySelector('img') as HTMLImageElement
imgUrl.src = "xxx"
// 1、断言只能断言成更加具体或者是不太具体的类型
// const age = 18 as string
const  age = 18 as any | unknown


非空类型断言:

interface IPerson {
  name : string,
  age : number,
  friend ?: {
    name : string
  }
}
const info : IPerson = {
  name : '张三',
  age : 18,
}
// 访问属性:可选链
console.log(info.friend?.name)
// 属性赋值
// info.friend?.name = '李四'   // 报错,因为friend是可选属性,不能赋值
// 解决方式1:类型缩小 
if(info.friend){
  info.friend.name = '李四'
}
// 解决方式2:非空断言 !(有点危险,确保friend一定有值才可以用)
info.friend!.name = '李四'

4、字面量类型和类型缩小

类型缩小:限制到一个较小的类型,确定其类型

if (typeof foo === 'number'){
    foo.toString()  //类型断言
}
平等缩小:===/!==
instanceof
in
const arr : string = "aaa"
// 1、typeof
if(typeof arr === "string"){
    console.log("是字符串")
}
// 2、平等缩小,一般用来判断字面量类型
type Direction = "left" | "right" | "up" | "down"
const switchDirection = (direction:Direction) => {
    if(direction === "left"){
        console.log("向左移动")
    }else if(direction === "right"){
        console.log("向右移动")
    }else if(direction === "up"){
        console.log("向上移动")
    }else if(direction === "down"){
        console.log("向下移动")
    }
}
// 3、instanceof
// 传入日期打印当前时间
const getDate = (date : string | Date) => {
  if(date instanceof Date){
    console.log(date.getDate())
  }
}
// 4、in
interface ISwim {
  swim : () => void
}
interface IRun {
  run : () => void
}
const dog : ISwim = {
  swim : () => {
    console.log("狗会游泳")
  }
}
const move = (animal : ISwim | IRun) => {
  if("run" in animal){
    animal.run()
  }else if ("swim" in animal){
    animal.swim()
  }
}
move(dog)

字面量类型:

// 定义字面量
type Direction = "left" | "right" | "up" | "down";
const d1 : Direction = "left"   //相当于枚举
// const d2 : Direction = "aaa"    //报错
type method = "get" | "post" | "put" | "delete";
const request = (url : string , method : method)  => {
} 
const info = {
  url:"xxx",
  method:"get"
}
// request(info.url , info.method)  //报错:类型“string”的参数不能赋给类型“method”的参数。
// 解决:
const info1 : {url : string , method : method} = {
  url:"xxx",
  method:"get"
}
const info2 = {
  url:"xxx",
  method:"get"
}as const 
request(info1.url , info1.method) // 正确
request(info2.url , info2.method) // 正确
export{}

5、函数的类型和函数签名

函数类型(难点):

// 1、函数类型表达式
// 格式:(参数列表:对应的形参名字加类型) => 返回值
// 起别名
type barType = (num1 : number) => number
const bar : barType  = (arg : number):number => {
    return arg;
} 
// 1、函数类型表达式
// 格式:(参数列表:对应的形参名字加类型) => 返回值
// 起别名
type barType = (num1 : number) => number
const bar : barType  = (arg : number):number => {
    return arg;
} 
// 练习
// 函数中传入函数
type calcFnType = (num1 : number , num2 : number) => number
const calc  = (calcFn : calcFnType ) => {
     const num1 = 10
     const num2 = 20
     const res = calcFn(num1 , num2)
     console.log(res)
}
const add = (num1 : number , num2 : number)  => {
    return num1 + num2
}
// 匿名函数
calc((num1 , num2) => {
  return num1 - num2
})
calc(add)
export{}

ts对于传入函数类型的多余的参数会被忽略掉

调用签名:指定函数类型的方法

函数本身也是一个对象,函数也会有其他的属性,调用签名就可以声明属性

interface IBar {
  name:string
  age:number
  // 函数可以调用,函数签名
  (num1 : number) :number
}
const bar: IBar = (num1 : number) : number => {
  return 123
}
bar.age = 18
bar.name = "111"
bar(123)

怎么分辨:

1、如果只是描述函数类型本身(函数可以被调用),使用函数类型表达式

2、如果在描述函数作为对象可以被调用,同时也有其他属性时,使用函数调用签名

构造签名:

class Person {
}
interface ICTPerson {
  new () :Person  //构造签名
}
const factory = (fn : ICTPerson) =>{
  const f = new fn()  //any
  return f;
}
factory(Person)

6、函数的重载和this

// 重载:
// 1、先编写重载签名
function cz(num1 : number , num2 : number) : number
function cz(num1 : string , num2 : string) : string
// 2、编写通用的函数实现
function cz(num1 : any , num2 : any) : any {
  return num1 + num2;
}

最好使用联合类型来代替函数重载

this相关的内置工具:

ThisParamenterType:用于提取一个函数类型Type的this参数类型

// 1、ThisParameterType获取函数的this类型
type FooThisType = ThisParameterType

OmitThisParameter:

type PureFooType = OmitThisParameter
// 3、ThisType 不会返回一个转换之后的类型,标记上下文中的this类型(绑定上下文中的this)

如果这个函数类型没有this参数返回unknown

ThisType:

// ThisType:绑定this上下文
interface IState {
  name : string;
  age: number;
}
interface IStore {
  state: IState;
  eating: () => void;
  running: () => void;
}
const store : IStore & ThisType = {
  state: {
    name: 'zhangsan',
    age: 18
  },
  eating: function() {
    // 如果不使用ThisType,那么this指向的是window对象,将改为this.state.this
    console.log(this.name + ' is eating');
  },
  running: function() {
    console.log(this.name + ' is running');
  }
}
store.eating.call(store.state);
export{}

你可能感兴趣的:(小白学习ts,typescript,前端)