React + ts学习笔记

前提准备:

环境配置

安装node.js

官网安装:当前使用版本18.15.0

安装新的react应用:

运行命令新建react-app

npx create-react-app study-ts-app

当前版本:

  • “react”: “^18.2.0”,
  • “react-dom”: “^18.2.0”,
    如果出现如下问题,无法安装依赖
    image.png
    可以尝试运行npm i react,如果报错,执行推荐命令
    image.png
    运行命令:
sudo chown -R 502:20 "/Users/rcdl/.npm"

命令详解参考:https://blog.csdn.net/wangcheeng/article/details/128165359
然后继续执行create-react-app

安装typeScript

npm i typescript --save
  • “typescript”: “^5.0.4”,

在react中使用ts

参考:https://juejin.cn/post/7021674818621669389

在类组件

参数没有都可以被省略

// 使用方式:React.Component<P, S={}>{...}

// 示例:
import * as React from 'react'
interface IProps {
  name: string;
}

interface IState {
  age: number;
}

class Hello extends React.Component<IProps, IState> {
  state = {
    age: 18
  };

  render() {
    return (
      <div>
        {this.state.age}
        {this.props.name}
      </div>
    );
  }
}

export default Hello;

React.Component中P是props类型的定义,S是state类型的定义,都是泛型接口

React.PureComponent<P, S={} SS={}>{...}

React.PureComponent前两个值含义相同,第三个值代表getSnapshotBeforeUpdate的返回值

在函数组件

在函数组件中,也可以接收一个参数(可省),参数表示props的类型,示例如下

interface IProps {
  name: string
}

const HelloFunction = (props: IProps) => {
  const {name} = props;

  return (
    <div className="App">
      <h1>hello world</h1>
      <h2>{name}</h2>
    </div>
  );
}

export default HelloFunction;

定义函数组件的第二种方式,React.FunctionComponent<P={}>来定义,也可以使用其简写React.FC<P={}>,参数可省,示例如下

interface IProps {
  name: string
}

const App: React.FC<IProps> = (props) => {
  const {name} = props;
  return (
    <div className="App">
      <h1>hello world</h1>
      <h2>{name}</h2>
    </div>
  );
}

export default App;

当使用这种形式来定义函数组件时,props中默认会带有children属性,它表示该组件在调用时,其内部的元素,来看一个例子,首先定义一个parent组件,组件中引入了Child1和Child2组件:

import Child1 from "../childFunction/child1";
import Child2 from "../childFunction/child2";

interface IProps {
  name: string;
}
const Parent: React.FC<IProps> = (props) => {
  const { name } = props;
  return (
    <Child1 name={name}>
      <Child2 name={name} />
      my test content
    </Child1>
  );
};

export default Parent;

child1组件如下

interface IProps {
  name: string;
}
const Child1: React.FC<React.PropsWithChildren<IProps>> = (props) => {
  const { name, children } = props;
  console.log(children);
  return (
    <div className="App">
      <h1>hello child1</h1>
      <h2>{name}</h2>
    </div>
  );
};

export default Child1;

这里的props.children是默认属性,输出结果是children的内容,就是parent组件中child1包裹起来的child2对象和文字
image.png

useState

如定义一个数字类型,有初始值可以直接写

const [flag, setFlag] = useState<number>(1)

没有初始值或初始值为null可以写成:

const [flag, setFlag] = useState<number | null>()

如初始化是一个对象
在确定对象中的属性类型和数量时,可以使用泛型定义

interface list {
    title: string,
    type: boolean
  }
  const [list, setList] = useState<list>({ title: '', type: false })
  setList({ title: '', type: true })

在未知对象属性数量和类型时
???

其他类型见下方扩展:ts基本类型

useRef

react写法

const frameRef = useRef(null);

ts写法

// 改变值时类型null不加也没显示报错--存疑?
const frameRef = useRef<HTMLInputElement | null>(null)

实例:

  const myText = useRef<HTMLInputElement | null>(null);
  console.log(myText.current) // null
  const changeText = (e) => {
  // myText的值会随着input中内容的输入实时改变
    myText.current.innerHTML = e.target.value;
  }

  return (
    <div>
      <input type="text" onChange={(e) => changeText(e)} />
      <h2 ref={myText} />
    </div>
  );

useMemo

useMemo返回的是一个值,所以需要有返回类型,如果返回类型和定义类型不同会报错

注:useCallback不需要定义返回值类型,因为他返回的是一个函数

const calculatedValue1 = useMemo<number>(() => a ** 2, [a]);

事件处理

常见的Event事件对象如下:

  • 剪切板事件对象:ClipboardEvent<T = Element>
  • 拖拽事件对象:DragEvent<T = Element>
  • 焦点事件对象:FocusEvent<T = Element>
  • 表单事件对象:FormEvent<T = Element>
  • Change事件对象:ChangeEvent<T = Element>
  • 键盘事件对象:KeyboardEvent<T = Element>
  • 鼠标事件对象:MouseEvent<T = Element, E = NativeMouseEvent>
  • 触摸事件对象:TouchEvent<T = Element>
  • 滚轮事件对象:WheelEvent<T = Element>
  • 动画事件对象:AnimationEvent<T = Element>
  • 过渡事件对象:TransitionEvent<T = Element>

例如:
MouseEvent是上面的鼠标事件对象(click事件)HTMLDivElement代表该函数作用于一个div元素

const handleChangeCurrent = (e: React.MouseEvent<HTMLDivElement>) => {}

事件处理函数的类型声明

type EventHandler<E extends SyntheticEvent<any>> = { bivarianceHack(event: E): void }["bivarianceHack"];

type ReactEventHandler<T = Element> = EventHandler<SyntheticEvent<T>>;
// 剪切板事件处理函数
type ClipboardEventHandler<T = Element> = EventHandler<ClipboardEvent<T>>;
// 复合事件处理函数
type CompositionEventHandler<T = Element> = EventHandler<CompositionEvent<T>>;
// 拖拽事件处理函数
type DragEventHandler<T = Element> = EventHandler<DragEvent<T>>;
// 焦点事件处理函数
type FocusEventHandler<T = Element> = EventHandler<FocusEvent<T>>;
// 表单事件处理函数
type FormEventHandler<T = Element> = EventHandler<FormEvent<T>>;
// Change事件处理函数
type ChangeEventHandler<T = Element> = EventHandler<ChangeEvent<T>>;
// 键盘事件处理函数
type KeyboardEventHandler<T = Element> = EventHandler<KeyboardEvent<T>>;
// 鼠标事件处理函数
type MouseEventHandler<T = Element> = EventHandler<MouseEvent<T>>;
// 触屏事件处理函数
type TouchEventHandler<T = Element> = EventHandler<TouchEvent<T>>;
// 指针事件处理函数
type PointerEventHandler<T = Element> = EventHandler<PointerEvent<T>>;
// 界面事件处理函数
type UIEventHandler<T = Element> = EventHandler<UIEvent<T>>;
// 滚轮事件处理函数
type WheelEventHandler<T = Element> = EventHandler<WheelEvent<T>>;
// 动画事件处理函数
type AnimationEventHandler<T = Element> = EventHandler<AnimationEvent<T>>;
// 过渡事件处理函数
type TransitionEventHandler<T = Element> = EventHandler<TransitionEvent<T>>;**

扩展:ts基本类型

布尔值true/false:boolean

let isDone: boolean = false;

数字:number

ts支持二进制、八进制、十进制和十六进制字面量。

let age: number = 6; 

字符串:string

let name: string = 'jack';

null和undefined

let u: undefined = undefined;
let n: null = null;

Symbol

Symbol是不可改变且唯一的。

let sym: symbol = Symbol()

数组:[]

定义数组的两种方式:

1 在元素类型后接上 []

2 使用数组泛型,Array<元素类型>

let list: number[] = [1, 2, 3];          //定义各项都是数字的数组。
let list: Array<number> = [1, 2, 3];     
let list: string[] = ['1', '2', '3'];          //定义各项都是字符串的数组。
let list: Array<string> = ['1', '2', '3'];    

元组 Tuple

元组类型可以定义已知元素数量和各元素类型的数组。

当访问已知索引的元素,会得到正确的类型;当访问越界的元素,会使用联合类型代替。

let data: [string, number];
data = ['jack', 20];

枚举:enum

枚举类型可以为一组数值赋予名字。默认情况下,元素从0开始编号,也可以手动指定元素的值。

enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green;

枚举类型还可以根据枚举的值得到他的名字。

enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];
console.log(colorName);  // Green

Any

any用于在不确定变量类型时使用。比如用户输入或第三方代码库引用,或者定义不同类型元素的数组。

ts默认这些值是不需要类型检查直接编译。

let notSure: any = 4;
notSure = "a string";
let list: any[] = [1, true, "jack"];

Unknown

与any类似,但是会做类型检查再编译。

function divide(param: unknown) {
  // return param / 2;  // 不知道params的类型使用了运算符会编译错误
  return param as number / 2;
}

Void

void表示没有任何类型。void类型只能赋值为null或undefined。

当一个函数没有返回值或者返回值是undefined时,他的返回值类型可以用void。

function warnUser(): void {
  console.log("This is my warning message");
}

Never

never类型表示永不存在的值的类型;如:

1 函数执行时抛出异常

2 函数中的代码无限循环,到不了返回值那一步

never是任何类型的子类型,可以赋值给任何类型。

// 异常
function fn(msg: string): never { 
  throw new Error(msg)
}

// 死循环
function fn(): never { 
  while (true) {}
}

Object

定义object对象类型的方式:

1 直接定义类型为object

2 将对象内属性的类型都逐个定义

let obj: object = { name: 'lin', age: 18 };
let person: { 
  age: number, name: string 
} = { age: 12, name: 'jack' };

类型扩展

类型断言

当绝对确认一个实体的类型时使用,使用方式有两种;

1.实体 as 类型(支持JSX)

2.<类型>实体

let someValue: any = "this is a string";
let strLength1: number = (someValue as string).length;
or
let strLength2: number = (<string>someValue).length;

类型别名

当定义的类型名过长或复杂时可以定义个别名,方便书写。

type s = string | number;
const str: s = 'jack';

也可以写成对象形式,定义具体的变量类型

type A = { name: string }

其他常用类型

联合类型

联合类型是由两个及以上种类型组成的类型,表示变量可以是其中的任意一种类型;且只能访问他们共有的方法和属性。

let timer: number | string | null = 1;

内置类型

ECMAScript的内置对象

const nums: Array<number> = [1,2,3]
const date: Date = new Date()
const err: Error = new Error('Error!');
const reg: RegExp = /abc/;

字面量类型

用type定义成一个字面量然后使用,能够减少代码量,降低耦合性。

type ButtonSize = 'mini' | 'small' | 'normal' | 'large'
const btnSize: ButtonSize = 'small'

函数

创建

ts可以创建有名字的函数和匿名函数。

function add(x: number, y: number): number {
  return x + y;
}

let myAdd = function (x: number, y: number): number {
  return x + y;
};

let myAdd1: (x: number, y: number) => number =
  function (x: number, y: number): number {
    return x + y;
  };

传参

已知参数个数

传递给一个函数的参数个数必须与函数期望的参数个数一致,不一致会报错。

function buildName(firstName: string, lastName: string) {
  return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // error
let result3 = buildName("Bob", "Adams");        

如果参数可传可不传,可以在参数名后加 ? ,实现参数可选功能,没传默认是undefined。

可选参数必须放在必须参数后面。

function buildName(firstName: string, lastName?: string) {
  if (lastName)
    return firstName + " " + lastName;
  else
    return firstName;
}
let result1 = buildName("Bob");                  
let result2 = buildName("Bob", "Adams", "Sr."); // error, 应有 0-2 个参数,但获得 3 个。
let result3 = buildName("Bob", "Adams");         

如果是带默认值的参数放在必须参数前,要求必须明确的传入undefined值获得默认值。

function buildName(firstName = "Will", lastName: string) {
    return firstName + " " + lastName;
}
let result4 = buildName(undefined, "Adams");

未知参数个数

如果传参个数不确定,可以把所有参数收集到一个变量中。

function buildName(firstName: string, ...restOfName: string[]) {
  return firstName + " " + restOfName.join(" ");
}

let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

泛型

泛型的关键目的是给成员之间提供有意义的约束。成员可以是:

1 类的实例成员

2 类的方法

3 函数参数

4 函数返回值

使用泛型可以创建可重用的通用组件,一个组件可以支持多种类型的数据,在定义的时候不预先指定具体的类型,而是在使用的时候再指定。不同于any,他不会丢失信息,传入和返回类型相同。

定义泛型函数

给函数添加类型变量T(type),可以捕获到用户传入的类型;并使用T作为返回值类型。

其他常见泛型变量:

1 K(Key):表示对象中的键类型;

2 V(Value):表示对象中的值类型;

3 E(Element):表示元素类型。

function identity<T>(arg: T): T {
    return arg;
}

使用泛型函数

使用泛型函数的方法有两种

1 传入所有参数和参数类型

2 传入参数,不传类型,编译器会根据传入的参数自动确定T的类型

let output = identity<string>("myString"); 
let output = identity("myString"); 

泛型接口

interface GenericIdentityFn {
  <T>(arg: T): T;
}

function identity<T>(arg: T): T {
  return arg;
}

let myIdentity: GenericIdentityFn = identity;

返回两种类型的对象

// 创建一个Identities 接口
interface Identities<V, M> {
  value: V,
  message: M
}
// 将 Identities 接口作为 identity 函数的返回类型
function identity<T, U> (value: T, message: U): Identities<T, U> {
  console.log(value + ": " + typeof (value));
  console.log(message + ": " + typeof (message));
  let identities: Identities<T, U> = {
    value,
    message
  };
  return identities;
}

console.log(identity(68, "Semlinker"));
// 68: number
// Semlinker: string
// {value: 68, message: "Semlinker"}

泛型类

泛型类与泛型接口类似。 泛型类使用(<T, …>)括起泛型类型,定义多个类型变量,跟在类名后面。

class GenericNumber<T> {
  zeroValue: T;
  add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

泛型约束

用于限制每个类型变量接受的类型数量。

如要求类型变量上对应的类型存在某些属性(length,push),在没有明确T类型时是不能使用length属性的。

function identity<T>(arg: T): T {
  console.log(arg.length); // Error
  return arg;
}

可以让类型变量extends一个含有所需属性(length)的接口(Length),可以获取到length属性。

但是如果调用identiy时传入参数不带有length属性会报错。

interface Length {
  length: number;
}
// 也可以使用多种约束类型
// <T extends Length, Type2, Type3, ...>
function identity<T extends Length>(arg: T): T {
  console.log(arg.length); // 可以获取length属性
  return arg;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CompletableFuture使用教学

CompletableFuture使用教学 一、开始一个线程异步执行不需要返回值 通过runAsync方式 //1.不加线程池方式 CompletableFuture<Void> completableFuture CompletableFuture.runAsync(() -> {System.out.println(Thread.currentThread().getName());//停顿几秒try {…

对象应用:C++字符串和vector,对象的new与delete重构

对象应用 C字符串和vector字符串创建方式字符串拼接字符串追加 字符串截断autovector创建方式vector操作 new与delete重构new与delete的工作步骤new与delete重构应用只能生成栈对象只能生成堆对象 C字符串和vector C的字符串是一个对象&#xff0c;存在于std标准库中&#xff0…

[echarts] legend icon 自定义的几种方式

echarts 官方配置项 地址 一、默认 图例项的 icon circle, rect, roundRect, triangle, diamond, pin, arrow, none legend: {top: 5%,left: center,itemWidth: 20,itemHeight: 20,data: [{icon: circle, name: 搜索引擎},{icon: rect, name: 直接访问},{icon: roundRect, n…

什么是FPGA?关于FPGA基础知识 一起来了解FPGA lattice 深力科 MachXO3系列 LCMXO3LF-9400C-5BG256C

什么是FPGA&#xff1f;关于FPGA基础知识 一起来了解FPGA lattice 深力科 MachXO3系列 LCMXO3LF-9400C-5BG256C FPGA基础知识&#xff1a;FPGA是英文Field&#xff0d;Programmable Gate Array的缩写&#xff0c;即现场可编程门阵列&#xff0c;它是在PAL、GAL、CPLD等可编程器…

二叉排序树查找成功和不成功的平均查找长度

理解二叉树的特性: 1)结点:包含一个数据元素及若干指向子树分支的信息。 2)结点的度:一个结点拥有子树的数据成为结点的度。 3)叶子结点:也称为终端结点,没有子树的结点或者度为零的结点。 4)分支结点:也称为非终端结点,度不为零的结点成为非终端结点。 5)结点…

【一起撸个DL框架】5 实现:自适应线性单元

CSDN个人主页&#xff1a;清风莫追欢迎关注本专栏&#xff1a;《一起撸个DL框架》GitHub获取源码&#xff1a;https://github.com/flying-forever/OurDL 文章目录 5 实现&#xff1a;自适应线性单元&#x1f347;1 简介2 损失函数2.1 梯度下降法2.2 补充 3 整理项目结构4 损失函…

DAD-DAS模型

DAD-DAS模型 文章目录 DAD-DAS模型[toc]1 产品服务:需求方程2 实际利率:费雪方程3 通货膨胀:菲利普斯方程4 预期通货膨胀&#xff1a;适应性预期5 货币政策规则&#xff1a;泰勒方程6 动态总供给-总需求方程&#xff08;DAS-DAD&#xff09;7 总供给冲击模拟 1 产品服务:需求方…

Elasticsearch:NLP 和 Elastic:入门

自然语言处理 (Natural Language Processing - NLP) 是人工智能 (AI) 的一个分支&#xff0c;专注于尽可能接近人类解释的理解人类语言&#xff0c;将计算语言学与统计、机器学习和深度学习模型相结合。 AI - Artificial Inteligence 人工智能ML - Machine Learning 机器学习DL…

永远不该忘记!科技才是硬道理,手中没有剑,跟有剑不用,是两回事

今天是全国防灾减灾日&#xff0c;距离2008年汶川大地震也已经过去15年了。但时至今日&#xff0c;看到那些图像视频资料&#xff0c;那种触及灵魂的疼痛仍是存在的&#xff0c;2008年的大地震在每个中国人身上都留下了无法抚平的伤疤。 2008年是所有中国人都无法忘记的一年&am…

Ims跟2/3G会议电话(Conference call)流程差异介绍

2/3G Conference call 合并(Merged)通话前,两路电话只能一路保持(Hold),一路通话(Active)。 主叫Merged操作,Hold的一路会变成Active,进入会议通话。 例如终端A跟C通话,再跟B通话,此时B就是Active状态,C从Active变成Hold状态。Merged进入会议通话后,C又从Hold变…

docker安装elasticsearch

前言 安装es么&#xff0c;也没什么难的&#xff0c;主要网上搜一搜&#xff0c;看看文档&#xff0c;但是走过的坑还是需要记录一下的 主要参考这三份文档&#xff1a; Running the Elastic Stack on Docker docker简易搭建ElasticSearch集群 Running Kibana on Docker …

Python-exe调用-控制台命令行执行-PyCharm刷新文件夹

文章目录 1.控制台命令行执行1.1.subprocess.Popen1.2.os.system()1.3.subprocess.getstatusoutput()1.4.os.popen() 2.PyCharm刷新文件夹3.作者答疑 1.控制台命令行执行 主要四种方式实现。 1.1.subprocess.Popen import os import subprocess cmd "project1.exe&qu…

只下载rpm包而不安装(用于内网虚拟机使用)

这里写目录标题 问题&#xff1a;解决&#xff1a;1. 安装yum-utils2. 下载rpm包3. 将rpm包拷贝到离线的虚拟机并安装 遇到的问题&#xff1a;1. error while loading shared libraries: libXXX.so.X: cannot open shared object file: No such file2. wrong ELF class: ELFCLA…

C++学习day--10 条件判断、分支

1、if语句 if 语句的三种形态 形态1&#xff1a;如果。。。那么。。。 #include <iostream> using namespace std; int main( void ) { int salary; cout << " 你月薪多少 ?" ; cin >> salary; if (salary < 20000) { cout <&…

【博客系统】页面设计(附完整源码)

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、页面介绍 二、预期效果 1、博客列表页效…

大项目准备(2)

目录 中国十大最具发展潜力城市 docker是什么&#xff1f;能介绍一下吗&#xff1f; 中国十大最具发展潜力城市 按照人随产业走、产业决定城市兴衰、规模经济和交通成本等区位因素决定产业布局的基本逻辑&#xff0c;我们在《中国城市发展潜力排名&#xff1a;2022》研究报告…

websocket

&#x1f449;websocket_菜鸟教程*…*的博客-CSDN博客 目录 1、什么是Socket&#xff1f;什么是WebSocket&#xff1f; 2、WebSocket的通信原理和机制 3、WebSocket技术出现之前&#xff0c;Web端实现即时通讯的方法有哪些&#xff1f; 4、一个简单的WebSocket聊天小例子 …

prometheus监控数据持久化

前置条件 1.规划两台主机安装prometheus # kubectl get nodes --show-labels | grep prometheus nm-foot-gxc-proms01 Ready worker 62d v1.23.6 beta.kubernetes.io/archamd64,beta.kubernetes.io/oslinux,kubernetes.io/archamd64,kubernetes.io…

5款办公必备的好软件,你值得拥有

随着网络信息技术的发展&#xff0c;越来越多的人在办公时需要用到电脑了。如果你想提高办公效率&#xff0c;那么就少不了工具的帮忙&#xff0c;今天给大家分享5款办公必备的好软件。 1.文件管理工具——TagSpaces TagSpaces 是一款开源的文件管理工具,它可以通过标签来组织…

Linux一学就会——系统文件I/O

Linux一学就会——系统文件I/O 有几种输出信息到显示器的方式 #include <stdio.h> #include <string.h> int main() {const char *msg "hello fwrite\n";fwrite(msg, strlen(msg), 1, stdout);printf("hello printf\n");fprintf(stdout, &q…