TypeScript基础+进阶

-----------------------------------------------------------------------------
ts 
typescript 是 js的超集
微软开源的
vscode也是微软开源的

js是弱类型的
js大多是错误都是类型错误
如var num = 10; num = 'test'  数据从一个类型改为另一个类型
上面的代码调用 num.tofixed(2)就会报错  “tofiexd not a function”因为字符串没有这个方法

ts属于静态类型的编程语言 js属于动态的编程语言
静态类型:编译期做类型检查
动态类型:执行时做类型检查

react:ts + hooks
vue:vue3 + ts
vue2对ts的支持不友好

写ts代码  用tsc转为js代码 浏览器只认识js代码

实际开发中是webpack 或者 vite来做
yarn create vite 项目名 --template vue-ts

ts
类型注解
:number就是一种
为变量添加类型约束
约定了什么类型就只能赋值什么类型 否则就会报错
约定了类型后代码的提示就会很清晰
比如let num: number = 18
number.  就会点出来所有能用的方法  比如tofixed等等
写代码的时候出错了就会报错(也就是编译时报错)

js已有简单类型
null、undefined、boolean、number、boolean
复杂类型
对象、数组、函数等

ts新增类型
联合类型
自定义类型
接口
元组
字面量类型
枚举
void

多个.ts存在 如果在ts文件内不写export {} 而且有相同变量就会报错 。 因为只有加了之后才会被看做是模块 不写就相当于 是全局变量 相同的全局变量名只能有一个

ts中数组的写法
数字数组 不能写undefined给数组
let numArr: number[] = [1, 2, 3]
字符串的两种写法
let strArr: String[] = ['q', 'w', 'e']
// 泛型
let strArr2: Array<String> = ['q', 'w', 'e']

联合类型
数组中有两个或者多个类型的数据
// num可以使数字或者字符串
let num: number | string = '18'

// 数组中可以有字符串和数字
let arr: (number | String)[] = ['123',4,5,6]

// 定时器id赋初始值 null 或者 -1
let timerId: number | null = null
// let timerId: number | null = -1
// let timerId: number = -1
timerId =setTimeout(() => {
  
}, 1000);

自定义类型
type CustomArray = (number | string)[]

let arr: CustomArray = ['123',4,5,6]

// 定义函数提前要给参数和返回值定义类型
function add(n1: number, n2: number):number {
  return n1 + n2
}
console.log(add(1,2));

// 指定整个函数的类型 给函数表达式用的 方便函数复用
type MyFn = (n1: number, n2: number) => number
const add: MyFn = function (n, n2){
  return n+n2
}

const sub: MyFn = function (n, n2){
  return n-n2
}

函数没有返回值用:void
如果函数返回值是undefined 要用:undefined

function greet(name:string): void{
  console.log(name+"hello");
}

可选表达式 给形参加 ? 说明这个参数可传可不传 不传的话是undefined
function add(n1: number, n2?: number): void{
 console.log(n1,n2);
}
add(1,2)

-----------------------------------------------------------------------------
对象类型
// 对象的几种写法
// 写法一
let obj: {} = {}

// 写法二 不换行的话类型注解要写 ;(分号)
let obj2: { name: string; age: number } = {
  name: 'zs',
  age:18
}

// 写法三  换行的话类型注解可以不写 ;(分号)
let obj3: {
  name: string
  age: number
} = {
  name: 'ls',
  age:20
}

对象中的方法的两种写法
普通写法
let obj: {
  say(): void
  add(n1: number, n2:number):number
} = {
  say() {
    console.log('hello, world');
  },
  add(n1, n2) {
    return n1 + n2
  }
}

箭头函数写法
let obj4: {
  say: () => void
  add: (n1: number, n2: number) => number
} = {
  say() {
    console.log('hello, world');
  },
  add(n1, n2) {
    return n1 + n2
  }
}

接口类型
接口以interface关键字声明
接口名称推荐以I(大写I)开头 如IPerson

interface IDog {
  name: string
  age: number
  type: string
  bark: () => void
}

const retriever: IDog = {
  name: '小金毛',
  age: 1,
  type: '金毛',
  bark() {
    console.log('wang wang wang');
  }
}

type 声明后接 =
type MyFn = (n1: number, n2: number) => number
interface 声明后直接接 {}  且不用加;(分号)
interface IDog {
  name: string
  age: number
  type: string
  bark: () => void
}

相同:都可以给对象指定类型
不同:type可以给函数指定类型别名 基本类型等 ,  interface只能给对象指定类型
type单词更短更简单 而且type语法更加的新 能用type就用type

接口继承
interface IPoint2D {
  x: number
  y: number
}

interface IPoint3D extends IPoint2D {
//  这里会继承IPoint2D 的x y
  z: number
}

元祖tuple
比数组更加严谨
let num: number[] = [1,2,3,4,5]
此时num中可以有任意个数字

元祖就不一样了
let num: [number, number] = [118.111, 36]
[]中写了几个就只能赋值几个数

类型推论
某些没有明确指出类型的地方 ts的类型推论机制会帮助提供类型
2中常见场景
1.声明变量并初始化时
2.决定函数返回值时

类型推论只在声明的时候会做
如下的num就会被推论为number
let num = 18
num = 'str' //  这里报错number不可以被赋值为string类型

如下的a被推论为any所以可以这么写
let a 
a = 'any'
a = 18

函数返回值也有推论 会自动根据return后的语句推论类型
如下被推论为number
function add(a: number, b: number) {
  return a + b
}

但是指定返回值后就不可以return别的类型 否则会报错

开发时能省略类型注解的地方就省略(充分利用ts的类型推论能力)
根据公司要求来 严格就无论怎样都要写 不严格就可以偷懒不写
如果不知道类型可以把鼠标放到变量名称上 利用vscode提示来查看类型

字面量类型
// 类型注解为 string
let str = "Hello Ts"

// 类型注解为 Hello Ts   值只能为 Hello Ts
const str2 = "Hello Ts"

// 作用类似上面的const 类型注解为 Hello Ts   值只能为 Hello Ts
let  str3:"Hello Ts" = "Hello Ts"


//  配合联合类型使用  类型注解为 '男' | '女' 值只能为 男 女
let gender: '男' | '女' = "男"

枚举类型
枚举要用到值的场景推荐用枚举  如果枚举当做类型来用的时候不推荐 推荐用type
enum

enum Direction { up,down,left,right }

function move(direction: Direction): void{
  console.log(direction);
  // up,down,left,right 分别对应0 1 2 3
}
move(Direction.down)

ts的类型在编译成js的时候 所有ts的类型会被擦除   ts的类型(type)不能用来当成值赋值使用
枚举不仅是可以当类型  还可以当值使用
type A = string
let a = A // A仅表示类型这里却作为值使用

数字枚举和应用
如果枚举中的属性赋了初始值下面的值都会在上一个的基础上+1
enum Direction {
  up = 10,
  down,
  left,
  right
}

function move(direction: Direction): void{
  console.log(direction);
  // up,down,left,right 分别对应10 11 12 13
}
move(Direction.up)
move(Direction.down)
move(Direction.left)
move(Direction.right)

也可以给每一个enum赋初始值
enum Direction {
  up = 10,
  down = 12,
  left = 18,
  right = 20
}

// enum用于性别的时候
// 男0 女1
enum Gender {
  mail,
  femail
}

function fn(gender: Gender):void {
  console.log(gender);
}

fn(Gender.mail)
fn(Gender.femail)
// 而不要写成下面这样 下面的0 1称为魔术数字 别人不知道0 和 1代表什么意思
// fn(0)
// fn(1)

字符串枚举
使用要注意一旦给某个值赋了字符串值就要给所有的值赋字符串值  因为字符串无法自增 而枚举类型不赋值 下一个就会等于上一个值+1
enum Direction {
  up = "上",
  down = "下",
  left = "左",
  right = "右",
}


enum Gender {
  男 ,
  女
}

console.log(Gender.男);// 0
console.log(Gender.女);// 1
console.log(Gender[0]);// 男
console.log(Gender[1]);// 女

any类型
不推荐使用any 
any
声明变量不给类型和默认值
函数参数不给类型

any用多了代码就会变成“anyScript”

类型断言
我比ts更清楚这个数据类型是什么 所以加上断言 给它一个更加具体的类型
as关键字 实现断言

例如a链接 获取dom元素的时候ts认为你获取的是HTMLElement 此时无法访问.herf 但是a链接实际是 HTMLAnchorElement
img获取dom元素的时候ts认为你获取的是HTMLElement 此时无法访问.src 但是img实际HTMLImageElement
导致不准确 但是我知道它是什么类型 而且需要访问该类型的属性 所以需要类型断言
let link = document.getElementById('link') as HTMLAnchorElement 就可以link.href了
let img = document.getElementById('img') as HTMLImageElement 就可以img.src了

断言另一种语法
let link = <HTMLAnchorElement>document.getElementById('link')

type User = {
  name: string
  age: number
  gender: string
}

// 这里不as User 就不能赋值空对象 下面也无法user.出name age gender 也无法修改name age gender
let user: User = {} as User

setTimeout(() => {
  user = {
    name: 'zs',
    age: 18,
    gender: '男'
  }
}, 1000);
  
泛型
让函数、接口、class 复用
常见泛型:函数 接口 class泛型
T相当于类型变量 相当于一个容器

//  定义的函数带泛型 传什么类型 返回什么类型
function fn<T>(value: T): T{
  return value
}

// 调用的时候也要带有泛型
const res = fn<number>(1)
const str = fn<string>('str')
console.log(res,str);

泛型函数简化使用
可以隐式识别类型 可以省略<类型> ts内部有类型推断机制
编译器推断不准确或者无法推断的时候需要传入类型参数
let res = fn(1)
let str = fn('str')

泛型约束
// 要添加的约束 为了保证所有传入的值都可以点出一个或多个属性 就要加泛型约束
interface ILength  { length: number }

// 不加约束的话 不知道value有没有.length 不一定能点出length所以会报错  加了之后一定可以.出length
function fn<Type extends ILength>(value: Type): Type{
  console.log(value.length);
  return value
}

type User = {
  name: string
  age: number
}

function showUser<T extends User>(user:T):void {
  console.log(user.name);
  console.log(user.age);
}

泛型可以有多个类型变量

keyof关键字
type User = {
  name: string
  age: number
}

// 这里的A就是name或者age
const A = keyof User

keyof Type 可以获取Type中的所有键
function fn2<Type, Key extends keyof Type>(obj: Type, key: Key):void {
  console.log(obj[key]);
  
}

泛型接口
接口中所有成员都可以使用类型变量
使用泛型接口时 需要指定具体的类型
interface User<T> {
  name: T
  age: number
  sayHi(): T
}

let num: number[] = [1, 2, 3]
let num2: Array<number> = [1, 2, 3]
let num3: Array<number> = [1, 2, 3]
之后push也只能push number类型的数据

ts 配合defineProps使用泛型
<script lang="ts" setup>
// const props = defineProps({
//   money: {
//     type: Number,
//     required: true
//   },
//   car: {
//     type: String,
//     required: true
//   }
// })

const props = defineProps<{
  money: number
  car?: string
}>()
</script>

car可以传可以不传

或者写成下面的样子
interface Props {
  money: number
  car?: string
}


https://vuejs.org/guide/extras/reactivity-transform.html#explicit-opt-in
这个网址有vite和webpack分别怎么配置 指定默认值的配置

const props = defineProps<Props>()
// 指定默认值
const { money, car = '小黄车' } = defineProps<Props>()

提供默认值car
car要想响应式要在vite.config.ts配置
export default defineConfig({
  plugins: [vue({
    reactivityTransform: true
  })]
})


ts 配合 defineEmits
defineEmits<
const emit = defineEmits<{
  (e: 'changeMoney', money: number): void
  (e: 'changeCar', car: string): void
}>()

const changeMoney = function () {
  emit('changeMoney', 10)
}

ts 配合 ref
如果ref是简单数据类型可以简写
如果ref是复杂类型 可能会推断不出类型 就需要指定泛型
let money = ref<number>(100)  等同于 let money = ref(100)
也可以写成
let money:Ref<number> = ref(100)

// 指定空数组 或者空对象  就要给泛型
type Todos = {
  id: string
  name: string
  done: boolean
}[]

const list = ref<Todos>([])
list.value = [{ id: 1, name: 'asd', done: false }]

ts 配合reactive
reactive 也是一样 空数组或者空对象就要给泛型 基本类型或者不是空数组空对象就可以给泛型

ts 配合 computed
会根据计算属性的返回值 推断类型
也可以写泛型

const money = ref(10)

const double = computed<number>(()=>{
return money.value*2
})

-----------------------------------------------------------------------------
// 如何查看事件对象的类型:技巧:查看$event的类型即可
鼠标悬浮到$event 就可以看到事件对象了
<h1 @mousemove="move($event)">我是一个标题</h1>

不知道dom类型时 怎么查看dom类型
可以document.createElement('h1').__proto__      //  HTMLHeadingElement

provide和inject可以看网址 不常用 常用pinia
https://vuejs.org/guide/extras/reactivity-transform.html#explicit-opt-in

可选链操作符?.(问号 点)用于获取数据
会判断前?.前面的属性(或方法)是不是null  或者 undefined  是的话就返回undefined 不是的话就返回?.后面的值

const user = {
  name: 'zs',
  cat: {
    name: '布偶',
  },
}

// user.cat?.name?.anchor?.bind?.c
// user.cat?.['name']
// user.arr?.[0]
// user.sayHi?.()  //  判断这个函数有没有有就调用
console.log(user.cat?.['name'])

非空断言 !感叹号
非空断言一定要保证该数据为非空
const imgRef = ref<HTMLImageElement | null>(null)
const imgUrl = imageRef.value!.src

ts的类型声明文件
ts有两种文件类型 .ts   .d.ts
.d.ts文件是类型提示(比如数组类型数据会提示有.push .pop等数组相关的方法)相关的文件

内置类型声明文件
ts为js运行时可用的所有标准化内置API都提供了声明文件 写个.就有提示

axios 也有.d.ts文件 外部导入的插件有的会自带.d.ts文件 写代码就会有提示了
jquery 这种老的库 就没有.d.ts文件

https://github.com/DefinitelyTyped/DefinitelyTyped/
帮市面上主流的库都添加了.d.ts文件

yarn add @types/包名 就可以了
例如:@types/react @types/loadsh

自定义类型声明文件  .d.ts
.d.ts文件中不可以写js代码 只能写声明语句 加上declare 就是声明的意思
/// 三斜线表达式(ts独有的)
跟<script>很像

.d.ts文件 
提供共享数据 
在types文件夹下建一个data.d.ts
export type Todos = {
  id: number
  name: string
  done: boolean
}[]

提供类型声明

使用场景“”
老项目js迁移为ts 跟js同级建一个.d.ts
成为一名库开发者

utils文件夹下建index.d.ts
在main.js 中导入的是js  TS会自动加载与.js同名的.d.ts文件 以提供类型声明文件
在.d.ts中使用declare 为js中已存在变量声明类型
type interface等只在ts出现的可以不加declare
let function在js和ts都出现的 要加declare

官方文档提供了一个页面,可以来查询 @types/* 库
https://www.typescriptlang.org/dt/

axios可以指定泛型的方法
axios.request() 等价于 axios()
axios.get
axios.post
axios.put
axios.delete

// 单行注释
/*
多行注释
多行注释
多行注释
多行注释
*/

/**
*文档注释
*/

用vite创建的仓库 默认没有帮你创建git仓库

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值