React 中 TypeScript 和装饰器及 Hooks

news2024/9/23 21:24:09

概念

TypeScript 是强类型语言,相对于JavaScript 弱类型语言,它具有类型检测的功能,扩展了JavaScript 的语法。

TS的安装与执行:

//全局安装typescript
npm install typescript -g

// 第二个因为  本来的node是不可能支持 ts那种民间语法的 所以ts-node包对node进行了处理
npm install -g ts-node

npm install -d tslib @types/node


//执行
ts-node 文件名

类型推断 *

当我们没有定义类型时,TS 会自动实现一个类型推断的过程,当 TS 无法类型推断时,需要手动使用类型注解

type 与 interface的异同 

interface :是接口,用于描述一个对象。

type :是类型别名,用于给各种类型定义别名,让 TS 写起来更简洁、清晰。

相同点:1、都可以定义一个对象或函数     2、都可以实现继承

1、定义函数
type addType = (num1:number,num2:number) => number

interface addType {
    (num1:number,num2:number):number
}
//调用
const add:addType = (num1, num2) => {
    return num1 + num2
}


2、继承
//interface 使用 extends 实现继承
interface Person { 
  name: string 
}
interface Student extends Person { 
  grade: number 
}
//type 使用交叉类型实现继承
type Person = { 
  name: string 
}
type Student = Person & { grade: number  }    用交叉类型

不同点:

1、interface 使用 extends 或 implements 实现继承, type 使用交叉类型实现继承

2、type 可以声明基本类型、联合类型、交叉类型、元组等,interface 不可以

3、interface 可以合并重复声明,type 不可以

基础数据类型 

  • 常用:boolean、number、string、array、enum(枚举)、any、void
  • 不常用:tuple(元祖)、null、undefined、never

对象类型 

  • 对象类型、数组类型、类类型、函数类型在 TS 中统称对象类型
  • TS 中用接口(interface )来定义对象类型

数组类型

interface IItem {
  id: number;
  name: string;
  isGod: boolean;
}
const objectArr: IItem[] = [{ id: 1, name: '俊劫', isGod: true }];
// or
const objectArr: Array<IItem> = [{ id: 1, name: '俊劫', isGod: true }];

const numberArr: number[] = [1, 2, 3];

const arr: (number | string)[] = [1, "string", 2];

元祖tuple

赋值的类型、位置、个数需要和定义(声明)的类型、位置、个数一致。

// 数组 某个位置的值可以是注解中的任何一个
const LOL: (string | number)[] = ["zed", 25, "darts"];

// 元祖 每一项数据类型必须一致
const LOL: [string, string, number] = ["zed", "darts", 25];

联合与交叉类型

  • 联合类型:某个变量可能是多个 interface 中的其中一个,用 | 分割
  • 交叉类型:由多个类型组成,用 & 连接
// anjiao 某胖博主爱好
interface Waiter {
  anjiao: boolean;
  say: () => {};
}

interface Teacher {
  anjiao: boolean;
  skill: () => {};
}

// 联合类型
function judgeWho(animal: Waiter | Teacher) {}
// 交叉类型 
// 同名类型会进行合并,同名基础类型属性的合并返回:never
// 同名非基础类型属性可以正常合并
function judgeWho(jishi: Waiter & Teacher) {}

可索引类型接口:需要使用下标

interface UserArr{
    //定义索引key为number类型,索引值为string类型
    [index:number]:string
}
var arr1:UserArr;
 arr1=["aa","bb","cc"];//数组自带下标也就是索引

var arr2: UserArr
 arr2={1:"hello",2:"world"};

console.log(arr1);
console.log(arr2);


/*
* ts中接口
*   可索引(数组对象)  复合接口
* */
interface hanleA {
 [index:number]:hanleB
}

interface hanleB {
 name: string,
 age: number,
 flag?: boolean
}


function handleReduce(arr: hanleA) {
 console.log(arr)
}

handleReduce([{name: 'shun', age: 12}, {name: 'enne', age: 12}])

类接口

  • 类接口中使用 implements 或 extends 关键字实现继承
interface Animal { //在typescript中可以通过类的接口 锁死类的写法类型 
    name: string;
    eat(s: string): string;
  
}

//实现接口使用implements关键字,继承 使用extends关键字
//狗类
class Dog implements Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    //实现接口中抽象方法
    eat(s) {
        return this.name + "吃肉:" + s;
    }
}
//猫类
class Cat implements Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    //实现接口中抽象方法
    eat(s) {
        return this.name + "吃鱼:" + s;
    }
}

var dog = new Dog("tom");
var cat = new Cat("kitty");
console.log(dog.eat("五花肉"));
console.log(cat.eat("乌鳢鱼"));

函数接口

//函数型接口 ,非常类似于java、c#中使用lambda表达式传入匿名函数

//对两个数进行运算得到另一个数  函数型接口
interface CalcTwo{
    (a:number,b:number):number;
}
function calcArr(arr:number[],calc:CalcTwo,initVal:number):number{
      var result=initVal; // 0 
      arr.forEach((value)=>{
          result = calc(result,value); //9 
      });
     return result;
}
//相加
var arr:number[]=[1,3,5,7,9];
var add=function(a:number,b:number):number{
      return a+b;
};

console.log("相加",calcArr(arr, add, 0));//25

//相乘
var multiply=function(a:number,b:number):number{
    return a*b;
};
console.log("相乘",calcArr(arr, multiply, 1));//945
//或者直接传入一个匿名函数亦可
var s1=calcArr(arr,function(a,b){
    return a*b;
},1);
console.log("s1",s1);//945

var s2=calcArr(arr,function (a,b) {
    return (a+1)*(b+1);
 },1);
console.log("s2",s2);//10170

补充写法:

书写方式一:
const cluo: {
    name: string,
    age: number,
} = {
    name: "cluo",
    age: 18,
};
console.log(cluo.name);


书写方式二:参数解构化
function add({ one, two }: { one: number, two: number }):number {
    return one + two;
  } 
const total = add({ one: 1, two: 2 });

never返回值类型

如果一个函数是永远也执行不完的,就可以定义返回值为never,那什么样的函数是永远也执行不完的那?我们先来写一个这样的函数(比如执行执行的时候,抛出了异常,这时候就无法执行完了)。

还有一种是一直循环,也是我们常说的死循环,这样也运行不完

//抛出异常
function errorFuntion(): never {
  throw new Error();
  console.log("Hello World");
}

//死循环
function forNever(): never {
  while (true) {}
  console.log("Hello  ");
}

枚举类型

  • 枚举类型是有对应的数字值的,默认是从 0 开始的。
  • 以下是一个案例:比如我现在去"澳门 "时,通过掷色子随机选择一项服务,进行程序化模拟

enum Status {
  MASSAGE,
  SPA,
  LAOHUJI,
}

function getServe(status: any) {
  if (status === Status.MASSAGE) {
    return "massage";
  } else if (status === Status.SPA) {
    return "spa";
  } else if (status === Status.LAOHUJI) {
    return "dabaojian";
  }
}

const result = getServe(Status.SPA);

console.log(`我要去${result}`);//我要去spa


console.log(Status.MASSAGE);//0
console.log(Status.SPA);//1
console.log(Status.LAOHUJI);//2

泛型

  • 泛型: 方法名<类型形参>,会在参数函数调用之前进行类型形参的调用
function join<T>(first: T, second: T) {// 此时所有的T都是string 
    return `${first}${second}`;
}
console.log(join<number>( 1,2))
  • 泛型接口
// 实现泛型接口的两种方式
// 方式一:定义一个泛型接口,用函数实现
interface Func {
    <T>(value: T): T
}

// 定义一个函数实现泛型接口
var f: Func = function<T>(value: T):T {
    return value;
}
f<string>("hello")
f<number>(666)

// 方式二:定义一个user类和数据库进行映射,用类实现
class MysqlDb <T>{
    add(info: T): boolean {
        console.log(info);
        return true;
    }
 }

 class User {
    usernam: string | undefined;
    password: string | undefined;
 }
 var u1 = new User();
 u1.usernam = "pika";
 u1.password = "pika"
 
 // 实例化一个数据库(类当成一个参数来约束传入参数的类型)
 var msql = new MysqlDb<User>();
 msql.add(u1);   // 保证传入数据的格式是User类型的

装饰器模式

  • 在JavaScript中,装饰器的语法比较特殊。它们的前缀是@符号,放在我们需要装饰的代码前面。

第一步:需要 tsc 初始化:tsc --init,会产生一个tsconfig.json文件

第二步:加入"experimentalDecorators": true,表示开启装饰器模式

 

第三步:装饰器模式的使用

function logClass(params: any) {
    console.log(params);
    // params 就是当前类
    params.prototype.apiUrl = '动态扩展的属性';
    params.prototype.run = function () {
        console.log('我是一个run方法');
    }

}
@logClass // 相当于logClass(HttpClient )
class HttpClient {
    constructor() {
    }
    getData() {

    }
}
var http: any = new HttpClient();
console.log(http.apiUrl);
http.run();

React 新特性 hooks

  • React 16.8之后出现了 hooks 钩子,React 17之后 hooks 较为稳定。
  • hooks 是为了解决函数式组件没有生命周期,无法实现数据的响应式。
  • 同时解决类组件中,难以复用组件间状态逻辑(组件状态逻辑的复用,需要 props render和高阶组件等解决方案,这将会导致层级冗余的问题),以及this指向的问题。
  • hooks 钩子使用 'use'前缀命名,如useXxx。
  • 常用的 hooks 钩子有useState、useEffect、useContext、useReducer、useRef、useMemo、useCallback等等

优点:

  • 不用考虑 this 指向问题
  • 解决了类组件中层级冗余的问题

缺点:

  • 只能函数组件中使用

状态钩子 useState

useState 函数可以声明组件状态,设置初始值,及【初始值,初始值修改函数】

import React,{useState} from 'react'

function App() {
  // count 0  setCount扳手 只有这个扳手才能拧动 count这个螺丝
  const [count,setCount] = useState(0)
  const addCount= ()=>{
    let newCount = count 
    setCount(newCount+1)
  }
  return (
    <div className="App">
       <div>{count}</div>
       <button onClick={addCount}>点击+1</button>
    </div>
  );
}

export default App;

共享状态组件的钩子 useContext:相当于类组件中的跨组件传值

import React,{useContext} from 'react'
function App() {
  //react自带的API返回一个 AppContext的上下文
  const AppContext = React.createContext()
  const Achild=()=>{
      const {name} = useContext(AppContext)
      return (
          <div>组件的名字  {name}</div>
      )
  }
  const Bchild=()=>{
    const {name2} = useContext(AppContext)
    return (
        <div>组件的名字  {name2}</div>
    )
}  
  return (
     <AppContext.Provider value={{name:"dddd",name2:'梅西'}}>
            <Achild></Achild>
            <Bchild></Bchild>
     </AppContext.Provider>
  );
}

export default App;

状态管理钩子 useReducer

import React,{useState,useContext,useReducer} from 'react'
function App() {
  
  const reducer = (state,action)=>{
     const   actionFn = {
          add:function(){
              return {
                  ...state,
                  count:state.count+1
              }
          }
      }
      return actionFn[action.type]()
  }

const [state,dispatch] = useReducer(reducer,{count:0})
  const addCount =()=>{
      dispatch({
          type:'add'
      })
  }
  return (
     <div>
         <div>{state.count}</div>
         <button onClick={addCount}>点击+1</button>
     </div>
  );
}

export default App;

副作用钩子 useEffect

  • useEffect 第一次执行会调用如同 vue2 中前四个生命周期函数,当数据更新时,在调用 updated 钩子函数,当销毁时调用 destroyed 钩子函数。
  • useEffect 相当类组件中的3个生命周期 componentDidMount 、componentDidUpdate、 componetWillUnMount
  • 此函数的操作是异步的。
import React,{useState,useEffect} from "react"; 
// useEffect 翻译 副作用钩子  直译 影响钩子 功能让函数组件中有类似于生命周期效果
function App() {
    const [loading,setLoading] = useState(true )
    //影响钩子 内部有一个回调匿名函数 
    // 第一次执行时机 dom生成之后  相当于模拟了mounted 生命周期 
    useEffect(()=>{ 
        console.log('useEffect')
        setTimeout(() => {
            setLoading(false)
        }, 3000);
    })
    return (
        <div>
            {
                loading ? (<div>loading.......</div>) : <div>加载成功</div>
            }
        </div>
    )
}

export default App 
// 影响钩子 不是生命周期 但是用买房子的三个阶段 来模拟生命周期
// 买房 回调函数开始执行  mounted 
// 装修 回调函数又执行    updated 
// 房子塌了 回调函数再次执行  destoryed 
useEffect 还可以指定调用如下案例:
import React,{useState,useEffect} from "react"; 
function App() {
    const [carBenzNum,setCarbenz] = useState(0)
    const [carqqnum,setCarqq] = useState(0)
    //影响钩子 内部有一个回调匿名函数 
    useEffect(()=>{ 
        console.log('useEffect')
        
    },[carBenzNum])
    const addBuyCar1 = () =>{
       setCarbenz(carBenzNum+1)
    }
    const addBuyCar2= () =>{
       setCarqq(carqqnum+1)
    }
    return (
        <div>
             <h1>影响钩子 副作用钩子</h1>
             <button onClick={addBuyCar1}>点击买奔驰</button>
             <button onClick={addBuyCar2}>点击买QQ车</button>
             <h1>家里的奔驰车数量{carBenzNum}</h1>
             <h1>家里的QQ车数量{carqqnum}</h1>
        </div>
    )
}
export default App 

记忆组件 useMemo(可以理解为计算属性)

import React, { useState, useMemo } from 'react';
const Memo = () => {
  const [count, setCount] = useState(1)
  const [val, setValue] = useState('')

  // 返回上一次缓存的值
  const sum = useMemo(() => {
    return count + 10
  }, [count]);

  return (
    <div>
      <h3>{count}-{val}-{sum}</h3>
      <div>
        <button onClick={() => setCount(count + 1)}>+ count</button>
        <input value={val} onChange={event => setValue(event.target.value)} />
      </div>
    </div>
  )
}

注:部分代码搬运自:一篇够用的TypeScript总结 - 掘金 (juejin.cn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/510571.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023网络安全学习路线 非常详细 推荐学习

前言&#xff1a;首先咱们聊聊&#xff0c;学习网络安全方向通常会有哪些问题 目录&#xff1a; 1、打基础时间太长 学基础花费很长时间&#xff0c;光语言都有几门&#xff0c;有些人会倒在学习 linux 系统及命令的路上&#xff0c;更多的人会倒在学习语言上&#xff1b; …

SSD系列1——网络结构

SSD系列&#xff1a; SSD系列1——网络结构 SSD系列2——PriorBox SSD系列3——损失计算 SSD网络结构概述 SSD在VGGNet的基础上&#xff0c;增加了4个卷积模块&#xff0c;这些卷积模块获得的特征图具有不同的感受野&#xff0c;可以较好地检测不同尺度的目标。 VGG16 SSD网络…

springboot 断点上传、续传、秒传实现

文章目录 前言一、实现思路二、数据库表对象二、业务入参对象三、本地上传实现三、minio上传实现总结 前言 springboot 断点上传、续传、秒传实现。 保存方式提供本地上传&#xff08;单机&#xff09;和minio上传&#xff08;可集群&#xff09; 本文主要是后端实现方案&…

AI绘画:Lora模型训练完整流程!

关于AI绘画(基于Stable Diffusion Webui)&#xff0c;我之前已经写过三篇文章&#xff0c;分别是 软件安装&#xff0c;基本的使用方法&#xff0c;微调模型LoRA的使用。 整体来说还是比简单的&#xff0c;搞个别人的模型&#xff0c;搞个提示词就出图了。今天来一个有些难度…

推荐11个好用的prompt工具网站(附链接+论文)

同学们&#xff0c;你们prompt是自己苦哈哈码的吗&#xff1f;可别了&#xff0c;有现成的工具为啥不用&#xff1f; 今天我就和大家分享一些好用的prompt工具网站&#xff0c;用熟了ChatGPT、midjourney、stable diffusion能玩起来更爽&#xff01;搜罗了有十几个&#xff0c…

智能汽车实验二(视觉传感器标定)

实验二 视觉传感器标定&#xff08;实验报告&#xff09; 【实验目的】 1、了解开源图像处理库OpenCV的结构&#xff0c;掌握OpenCV的基本使用方法。 2、了解开源图像处理库OpenCV的基本模块功能&#xff0c;掌握常用图像处理方法。 3、掌握摄像机标定算法&#xff0c;学会使用…

Xilinx 7系列FPGA内置ADC

Xilinx 7系列FPGA全系内置了一个ADC&#xff0c;称之为XADC。这个XADC&#xff0c;内部是两个1mbps的ADC&#xff0c;可以采集模拟信号转为数字信号送给FPGA内部使用。 XADC内部可以直接获取芯片结温和FPGA的若干供电电压&#xff08;7系列不包括VCCO&#xff09;&#xff0c;用…

麒麟KylinV10SP1(2203)推荐安装一些硬件监控类软件与使用

目录 前言 1、tlp 电源管理 &#xff08;1&#xff09;查看电池容量、使用量、为Thinkpad设定电池充电开始结束阈值 &#xff08;2&#xff09;查看硬盘比如NVME SSD的型号种类、当前温度、读写量等信息&#xff1b; &#xff08;3&#xff09;查看CPU型号以及频率上下限、…

软件测试简单么,发展前景如何?

随着人工智能时代的到来&#xff0c;IT行业受到了越来越多人的重视。软件测试作为把控软件质量必不可少的环节&#xff0c;其重要性可见一斑。 软件测试可以说是算得上IT行业里相对简单的语言&#xff0c;但是也只是相对哈&#xff0c;如果想学习下去还是要看个人的学习能力的…

软件测试工作内容和职责有哪些

目前&#xff0c;在IT行业中测试的职位数量仅次于开发&#xff0c;可以说是第二大技术就业岗位。然而许多人对测试师工作的理解还停留在&#xff0c;只需要像用户一样使用产品&#xff0c;然后发现有问题提交报告就行了。其实这是极其不准确的&#xff0c;软件测试师在测试产品…

通过Dnspy调试解决powershell使用Install-module指定的转换无效的问题

之前运行Install-module -Name NtObjectManager出现以下错误&#xff1a; PackageManagement\Install-Package : Package NtObjectManager failed to be installed because: 指定的转换无效。 At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.…

Shell编程之排序

目录 一、冒泡排序 二、选择排序 三、插入排序 基本思想&#xff1a; 四、反转排序 基本思想&#xff1a; 五、睡眠排序 六、希尔排序 基本思想&#xff1a; 举例 一、冒泡排序 冒泡排序&#xff0c;该排序的命名非常形象&#xff0c;即一个个将气泡冒出。冒泡排序一…

ChatDOC工具——使用ChatGPT高效阅读技术科研论文

ChatDOC是一款功能强大的人工智能阅读辅助工具&#xff0c;专为帮助用户快速理解论文内容而设计。使用ChatDOC&#xff0c;您可以通过上传PDF版论文文献&#xff0c;利用先进的ChatGPT技术&#xff0c;只需三个简单步骤&#xff0c;便可以高效地阅读论文&#xff0c;提高阅读效…

TypeScript初识

目录 介绍 定义 优点 类型声明 ts文件编译选项 自动编译 编译选项的各个属性 include compilerOptions 介绍 定义 TS&#xff08;TypeScript&#xff09;是一种由微软开发的编程语言&#xff0c;它是 JavaScript 的一个超集&#xff0c;提供了静态类型检查、类、接…

Linux系统编程——多线程[中]:互斥与同步

0.关注博主有更多知识 操作系统入门知识合集 目录 1.并发过程中的问题 2.互斥 2.1互斥锁 2.2如何看待互斥锁 2.3加锁和解锁的本质 2.4对锁做一个封装 2.5可重入函数与线程安全 2.6死锁 3.同步 3.1条件变量 1.并发过程中的问题 我们知道&#xff0c;同一个进程中的…

【SpringBoot】过滤器,监听器,拦截器介绍

文章目录 一、简介1、过滤器2、拦截器3、监听器 二、如何创建1、过滤器2、监听器3、拦截器 三、总结 一、简介 通过两幅图我们可以理解拦截器和过滤器的特点 1、过滤器 过滤器是在请求进入tomcat容器后&#xff0c;但请求进入servlet之前进行预处理的。请求结束返回也是&…

模拟IC与数字IC设计该怎么选?哪个岗位薪资高?

很多同学想要入行IC&#xff0c;但不知道数字和模拟方向怎么选&#xff1f; 如果没有亲身体会过模拟设计&#xff0c;并有发自内心的自信或者兴趣&#xff0c;一般不看好纯小白去学模拟电路设计。 模拟设计想做好&#xff0c;没有数学功底&#xff0c;没有电路分析的功底&…

面试题30天打卡-day24

1、Redis 为什么快&#xff1f; Redis 之所以快&#xff0c;主要是因为它具有以下特点&#xff1a; 纯内存操作&#xff1a;Redis 的数据存储在内存中&#xff0c;因此读写速度非常快&#xff0c;而无需像传统数据库一样从硬盘读取和写入数据。与此同时&#xff0c;Redis 支持…

【算法】动态规划算法求(编辑距离)

目录 编辑距离&#xff1a; 举例&#xff1a; 代码如下 调试&#xff1a; 核心代码&#xff1a; 画图演示上述代码&#xff1a; 编辑距离&#xff1a; 是一种计算两个自符串之间差异程度的方法&#xff0c;它通过比较两个字符串之间的插入&#xff0c;删除和 替换操作的数…

深度神经网络模型部署——Docker学习

容器技术中有三个核心概念&#xff1a;容器&#xff08;Container&#xff09;、镜像&#xff08;Image&#xff09;&#xff0c;以及镜像仓库&#xff08;Registry&#xff09; 从本质上来说&#xff0c;容器属于虚拟化技术的一种&#xff0c;和虚拟机&#xff08;Virtual Mac…