TypeScript 学习笔记(七):条件类型

条件类型

TS中的条件类型就是在类型中添加条件分支,以支持更加灵活的泛型,满足更多的使用场景。内置条件类型是TS内部封装好的一些类型处理,使用起来更加便利。

一、基本用法

当T类型可以赋值给U类型时,则返回X类型,否则返回Y类型。

T extends U ? X : Y
  • T U X Y 四个是占位符,分别表示四种类型;
  • T extends U表示T类型能被赋值给U类型,这里还涉及到TS类型兼容性。

这个表达式的意思是,如果 T 可以赋值给 U 类型,则是 X 类型,否则是 Y 类型。来看个实际例子:

T的具体类型返回不同类型的字符串,也就是字面量类型

type TypeName<T> =
  T extends string ? "string" :
  T extends number ? "number" :
  T extends boolean ? "boolean" :
  T extends undefined ? "undefined" :
  T extends Function ? "function" :
  "object";

type A = TypeName<'1'> //"string"
type B = TypeName<1> //"number"
type C = TypeName<true> //"blolean"
type D = TypeName<undefined> //"undefined"
type E = TypeName<()=>void> //"function"
type F = TypeName<{}> //"object "

T联合类型时 :

type G = TypeName<'1'1true> // "string" | "number" | "boolean"
type H = TypeName<()=>void | {}> // "function" | "object"

根据类型参数判断返回类型:

二、分布式条件类型

什么样的条件类型称为分布式条件类型呢?

答案是:条件类型里待检查的类型必须是裸类型naked type parameter

1. 什么类型是裸类型?

裸类型是指类型参数没有被包装在其他类型里,比如没有被数组、元组、函数、Promise等等包裹,简而言之裸类型就是未经过任何其他类型修饰或包装的类型。

当分布式条件类型中被检查类型为联合类型,则在运算过程中分解多个分支 。

type typeName<T> = T extends number ? "X" : "Y" ;
type H = typeName<string | number> // "X" | "Y"

//上面typeName在计算类型时,会分解为如下:
type H =  string extends number ? "X" : "Y" | number extends number ? "X" : "Y" 
= "X" | "Y"
// 裸类型参数,没有被任何其他类型包裹,即T
type NakedType<T> = T extends boolean ? "YES" : "NO"
// 类型参数被包裹的在元组内,即[T]
type WrappedType<T> = [T] extends [boolean] ? "YES" : "NO";

2. 分布式如何理解?

分布式条件类型在实例化时会自动分发成联合类型

什么意思呢?

T extends U ? X : Y使用类型参数A | B | C 实例化 T 解析为 (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)

结合 乘法分配律 理解一下!

接下来结合具体实例我们来看一下分布式条件类型不含有分布式特性的条件类型

  // 裸类型参数,没有被任何其他类型包裹,即T
  type NakedType<T> = T extends boolean ? 'YES' : 'NO';
  // 类型参数被包裹的在元组内,即[T]
  type WrappedType<T> = [T] extends [boolean] ? 'YES' : 'NO';

  // 含有分布式特性的,待检查类型必须为”裸类型“
  type Distributed = NakedType<number | boolean>; //  = NakedType<number> | NakedType<boolean> =  "NO" | "YES"(结合一下乘法分配律便于理解与记忆哦~)

  // 不含有分布式特性的,待检查的类型为包装或修饰过的类型
  type NotDistributed = WrappedType<number | boolean>; // "NO"

搞明白了分布式条件类型,我们编写这样一个类型工具 NonNullable ,即从类型 T 中排除 null 和 undefined ,我们期待的结果如下:

type a = NonNullable<string | number | undefined | null> // 得到type a = string | number

借助条件类型可以很容易写出来:

type NonNullable<T> = T extends null | undefined ? never : T

注意:never 类型表示不会是任何值,即什么都没有

三、非分布式条件类型

当T被数组、元组、Promise等包裹时,则运算过程中不会分解成多个分支,则该条件类型为非分布式条件类型。

type WrappedTuple<T> = [T] extends [boolean] ? "X" : "Y";
type WrappedArray<T> = T[] extends boolean[] ? "X" : "Y";
type WrappedPromise<T> = Promise<T> extends Promise<boolean> ? "X" : "Y";
type G = WrappedTuple<string | boolean>; // "Y"
type K = WrappedArray<string | boolean>; // "Y"
type L = WrappedPromise<string | boolean>; // "Y"

解析:

//由于计算数据时不会分解成多个分支

// [T] extends [boolean]
//WrappedTuple<string | boolean> 中 string | boolean 不是 boolean 类型,也不是其他原始类型

//T[] extends boolean[]
//WrappedArray<string | boolean> 中 string | boolean 不是 boolean 类型,也不是其他原始类型

//Promise<T> extends Promise<boolean>
//WrappedPromise<string | boolean> 中 string | boolean 不是 boolean 类型,也不是其他原始类型

四、结合泛型使用

1. 过滤出公共类型

在联合类型T过滤出联合类型U中的成员,过滤出来的成员则组成新的类型。下面例子中,如果类型T为类型U的子类型,则返回类型T,否则返回never

type Filter<T, U> = T extends U ? T : never;
type B = Filter<"a" | "b" | "c", "a" | "c" | "d"> ; // "a" | "c"

2. 类型删除

在联合类型T删除联合类型U中的成员,T类型中的剩余成员则组成新的类型。下面例子中,如果类型T为类型U的子类型,则返回never,否则返回类型T

type Diff<T, U> = T extends U ? never : T;
type A = Diff<"a" | "b" | "c", "a" | "c" | "d">;  // "b"

五、结合 infer 关键字

1. 根据类型参数判断返回类型

  1. 案例一:

条件类型提供一个infer关键字用来推断类型,我们先来看个例子。我们想定义一个条件类型,如果传入的类型是一个数组,则返回它元素的类型;如果是一个普通类型,则直接返回这个类型。来看下不使用 infer 的话,怎么写:

type Type<T> = T extends any[] ? T[number] : T;
type test = Type<string[]>; // test的类型为string
type test2 = Type<string>; // test2的类型为string

这个例子中,如果传入 Type 的是一个数组类型,那么返回的类型为T[number],也就是该数组的元素类型,如果不是数组,则直接返回这个类型。这里我们是自己通过索引访问类型T[number]来获取类型的,如果使用 infer 关键字则无需自己手动获取,我们来看下怎么使用 infer:

type Type<T> = T extends Array<infer U> ? U : T;
type test = Type<string[]>; // test的类型为string
type test2 = Type<string>; // test2的类型为string

这里 infer 能够推断出 U 的类型,并且供后面使用,你可以理解为这里定义了一个变量 U 来接收数组元素的类型。

  1. 案例二:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

const foo = (): string => {
  return "hello";
}

const bar = (): number => {
  return 42;
}

const str: ReturnType<typeof foo> = "hello"; // string
const num: ReturnType<typeof bar> = 42; // number

在这个例子中,我们定义了一个 ReturnType 类型,它接受一个泛型类型参数 T。这个类型参数代表一个函数类型,我们通过 T extends (…args: any[]) => infer R 这个条件语句来判断 T 是否是一个函数类型,并提取其返回值类型 R。如果 T 是一个函数类型,则返回 R 类型,否则返回 never 类型。

然后,我们定义了两个函数 foobar,分别返回字符串和数字。我们使用 typeof 操作符来获取这两个函数的类型,并通过 ReturnTypeReturnType 来获取它们的返回类型。

最后,我们声明了两个变量 strnum,并分别将它们声明为 ReturnTypeReturnType 类型。这样就可以根据不同的函数类型来确定返回类型。

  1. 案例三:
 type IsOptional<T> = T extends { [k: string]: infer U } ? undefined extends U ? true : false : never;

interface Person {
  name: string;
  age?: number;
}

const person1: Person = { name: "Alice" };
const person2: Person = { name: "Bob", age: 30 };

const isOptional1: IsOptional<typeof person1> = true; // true
const isOptional2: IsOptional<typeof person2> = true; // false

在这个例子中,我们定义了一个 IsOptional 类型,它接受一个泛型类型参数 T。这个类型参数代表一个对象类型,我们通过 T extends { [k: string]: infer U } 这个条件语句来判断 T 是否是一个对象类型,并提取其属性类型 U。然后,我们再使用 undefined extends U ? true : false 来判断属性类型 U 是否包含 undefined,如果包含则返回 true,否则返回 false。最后,如果 T 是一个对象类型,则返回 truefalse 类型,否则返回 never 类型。

然后,我们定义了一个 Person 接口,它包含一个必须属性 name 和一个可选属性 age。我们声明了两个变量 person1person2,分别表示一个只有必须属性的 Person 对象和一个同时包含必须属性和可选属性的 Person 对象。

最后,我们使用 IsOptionalIsOptional 分别获取这两个对象的属性是否可选,并将它们声明为 truefalse 类型。这样就可以根据对象类型的属性是否可选来确定返回类型。

2. 根据条件类型判断函数参数类型

  1. 案例一:
type FunctionReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

定义了FunctionReturnType条件类型,它会检查类型T是否为函数类型,如果是则通过infer获取函数的返回值类型R,否则返回never类型。具体案例如下:

type FRT1 = FunctionReturnType<() => number> //number

type FRT2 = FunctionReturnType<(x: string, y: number) => string[]> //string

type FRT3 = FunctionReturnType<() => void>//void

type FRT4 = FunctionReturnType<() => {}>//{}

type FRT5 = FunctionReturnType<1>//never
  1. 案例二:
 type ArgumentType<T> = T extends (arg: infer U) => any ? U : never;

const foo = (arg: string) => {
  return arg.toUpperCase();
}

const str: ArgumentType<typeof foo> = "hello"; // string

在这个例子中,我们定义了一个 ArgumentType 类型,它接受一个泛型类型参数 T。这个类型参数代表一个函数类型,我们通过 T extends (arg: infer U) => any 这个条件语句来判断 T 是否是一个函数类型,并提取其参数类型 U。如果 T 是一个函数类型,则返回参数类型 U,否则返回 never 类型。

然后,我们定义了一个 foo 函数,它接受一个字符串类型的参数,并将其转换为大写字母。我们使用 typeof 操作符来获取 foo 函数的类型,并通过 ArgumentType 来获取其参数类型。

  1. 案例三:

下面的示例演示在协变位置同一类型变量的多个候选类型将会被推断为联合类型

type Foo<T> = T extends { a: infer U, b: infer U } ? U : never;
type t1 = Foo<{ a: string, b: string }>;  // string
type t2 = Foo<{ a: string, b: number }>;  // string | number

同样在逆变位置同一类型变量的多个候选类型将会被推断为交叉类型

type Bar<T> = T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U : never;
type t1 = Bar<{ a: (x: string) => void, b: (x: string) => void }>;  // string
type t2 = Bar<{ a: (x: string) => void, b: (x: number) => void }>;  // string & number

协变与逆变

3. 根据类型的属性来判断函数的返回类型

假设我们有一个名为 fetchData 的函数,它从服务器获取数据并将其解析为特定类型。我们希望函数的返回类型根据请求的不同而有所区别,因此我们可以使用条件类型来实现这一点。

interface User {
  name: string;
  age: number;
}

interface Post {
  title: string;
  content: string;
}

type RequestType = "user" | "post";

const fetchData = <T extends RequestType>(type: T): T extends "user" ? User : Post => {
  // 根据请求类型获取不同的数据
  if (type === "user") {
    return { name: "John", age: 30 } as any;
  } else {
    return { title: "TypeScript is awesome", content: "..." } as any;
  }
}

const user = fetchData("user"); // User 类型
const post = fetchData("post"); // Post 类型

在这个例子中,我们定义了一个名为 fetchData的函数,它接受一个泛型类型参数 T,这个类型参数代表请求的类型,可以是 userpost。我们使用条件类型 T extends “user” ? User : Post 来决定返回的类型,如果请求的类型是 user,则返回 User 类型,否则返回 Post 类型。

然后,我们在函数体中根据请求类型获取不同的数据,返回的类型也会根据请求类型发生变化。

最后,我们分别调用 fetchData函数,并将其返回值分别赋值给 userpost 变量,这样就可以根据请求类型获取不同的数据,并且保证返回类型的正确性。

4. 根据类型的成员来判断其他类型

假设我们有一个名为 HasName 的类型,它表示一个具有 name 属性的类型。我们希望定义一个名为 PickWithName 的类型,它接受一个泛型类型参数 T,并从中选择具有 name 属性的子类型。

interface User {
  name: string;
  age: number;
}

interface Post {
  title: string;
  content: string;
}

type HasName = { name: string };

type PickWithName<T> = T extends HasName ? T : never;

type UserWithName = PickWithName<User>; // User 类型
type PostWithName = PickWithName<Post>; // never 类型

在这个例子中,我们定义了一个 HasName类型,它代表具有 name属性的类型。然后,我们定义了一个名为 PickWithName 的类型,它接受一个泛型类型参数 T,并使用条件类型 T extends HasName ? T : never 来判断 T 是否具有 name属性,如果是,则返回 T,否则返回 never 类型。

最后,我们分别使用 PickWithName 类型别名 PickWithName 来选择具有 name属性的子类型,并将其分别赋值给 UserWithNamePostWithName 变量。

5. 根据类型的可选属性来添加或删除属性修饰符

假设我们有一个名为 Person 的类型,它有两个属性 nameage,其中 name 属性是必需的,而 age 属性是可选的。我们希望定义一个名为 MakeFieldsOptional 的类型,它接受一个泛型类型参数 T,并将 T 中所有可选属性的修饰符从必需改为可选,将所有必需属性的修饰符保持不变。

type Person = {
  name: string;
  age?: number;
};

type MakeFieldsOptional<T> = {
  [P in keyof T]?: T[P];
};

type OptionalPerson = MakeFieldsOptional<Person>; // { name?: string; age?: number; }

在这个例子中,我们首先定义了一个 Person 类型,它有一个必需的 name 属性和一个可选的 age 属性。

然后,我们定义了一个名为 MakeFieldsOptional 的类型,它使用映射类型 [P in keyof T]?: T[P],将 T 中所有可选属性的修饰符从必需改为可选,将所有必需属性的修饰符保持不变。

最后,我们使用 MakeFieldsOptional 类型别名来将 Person 类型中所有可选属性的修饰符从必需改为可选,将其赋值给 OptionalPerson 变量。

6. 元组转为联合类型 tuple转union

[string, number] -> string | number

type ElementOf<T> = T extends Array<infer P> ? P : never;
type Tuple = [string, number];
type TupleToUnion = ElementOf<Tuple>; // type TupleToUnion = string | number

7. 联合类型转成交叉类型

string | number -> string & number

type T1 = { name: string };
type T2 = { age: number };
type ToIntersection<T> = T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U : never;
// 由于U需要同时满足T1的定义、T2的定义,因此U需要包含T1、T2所有的类型,因此T3就是T1 & T2
type T3 = ToIntersection<{ a: (x: T1) => void, b: (x: T2) => void }>; // type T3 = T1 & T2

重点:

  • U extends any 是具有分布式有条件类型特性,因为待检查类型 U 为裸类型
  • (U extends any ? (k: U) => void : never) extends ((k: infer I)=> void) 最后一个 extends 前面作为待检查类型,因为被函数包装,因此不具有分布式有条件类型特性
   type UnionToIntersection<U> = ((k: string) => void | (k: number) => void) extends ((k: infer I) => void) ? I : never;

根据 逆变特性 推断出的 I 应该具备 stringnumber 的类型,故为交叉类型 string & number,而该交叉类型在 vscode 中表现为 never

六、结合keyof关键字

1. 获取对象属性类型

keyof主要是获取某个对象/类型的属性名来构成新类型。我们可以使用条件类型和 keyof 关键字来获取对象的属性。具体案例如下:

type PropertyType<T, K extends keyof T> = K extends keyof T ? T[K] : never;

上面代码定义了类型为PropertyType<T, K extends keyof T>,通过检查K是否是T的一个属性名,如果是则返回该属性类型,否则返回never

type Obj = { a: string; b: number };
type A = PropertyType<Obj, "a">; // string
type B = PropertyType<Obj, "c">; // never

2. 实现映射类型

映射类型是泛型类型的一种,可用于把原有的对象类型映射成新的对象类型。我们可以使用条件类型和 keyof关键字来实现Partial类型,Partial类型是TS工具类之一。具体案例如下:

type Partial<T> = {
 [K in keyof T]? : T[K]
}

定义类型Partial,遍历T中所有属性,然后通过?将所有属性变成可选属性。

type obj = {a:string,b:number}
type R = Partial<obj>//{a?:string,b?:number}

注意:Partial是TS的工具类,所以声明Partial是会报错的,可以换个标识符名称。
在这里插入图片描述

七、内置条件类型

 // 找出T中不包含U的部分
  type Diff<T, U> = T extends U ? never : T;
  type R1 = Diff<'a' | 'b' | 'c' | 'd', 'a' | 'b' | 'c'>; // R1: 'd'
  // 由于U中的'a','b','c'都是T中的子类型,因此R1的类型就是'd'

  // 找出T中包含U的部分
  type Filter<T, U> = T extends U ? T : never;
  type R2 = Filter<'a' | 'b' | 'c' | 'd', 'a' | 'b' | 'c'>; // R2: 'a' | 'b' | 'c'

1. Exclude

  • 从T中排除掉U,和上面的Diff相同
type Exclude<T, U> = T extends U ? never : T;
type R3 = Exclude<'a' | 'b' | 'c' | 'd', 'a' | 'b' | 'c'>; // R3: 'd'

2. Extract

  • 从T中找出包含U的部分,和上面的filter相同
type Extract<T, U> = T extends U ? T : never;
type R4 = Extract<'a' | 'b' | 'c' | 'd', 'a' | 'b' | 'c'>; // R4: 'a' | 'b' | 'c'

3. NonNullable

  • 从T中找出不为null和undefined的参数
type NonNullable<T> = T extends null | undefined ? never : T;
type R5 = NonNullable<'a' | null | undefined | 'd'>; // R5: 'a' | 'd'

4. ReturnType 和 Parameters

  • infer:推断的意思,是一个关键字
  • ReturnType 获取函数的返回类型
  • Parameters 获取函数参数类型,返回一个元组
  // 1.1
  // ReturnType 获取函数的返回类型
  type ReturnType<T> = T extends (...args: any[]) => infer R ? R : T;
  function getUser() {
    return {
      name: '张三',
      age: 10
    }
  }
  // TS可以从参数中推断返回值类型
  type ReturnUser = ReturnType<typeof getUser>; // type ReturnUser = {name: string;age: number;}

  // 1.2
  // Parameters 获取函数参数类型,返回一个元组
  type Parameters<T> = T extends (...args: infer P) => any ? P : never;
  function getPerson(a: string, b: number) {
    return {
      name: '李四',
      age: 18
    }
  }
  type ParamsType = Parameters<typeof getPerson>; // type ParamsType = [a: string, b: number]

5. InstanceType 和 ConstructorParameters

  • InstanceType 获取构造函数的实例类型
  • ConstructorParameters 获取类的构造函数的参数类型
namespace e {
  class Person {
    name: string;
    constructor(name: string) {
      this.name = name;
    }
    getName() {
      console.log(this.name);
    }
  }

  // ConstructorParameters 获取类的构造函数的参数类型
  type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (
    ...args: infer P) => any ? P : never;
  type Params = ConstructorParameters<typeof Person> // type Params = [name: string]

  // InstanceType 获取构造函数的实例类型
  type Instance = InstanceType<typeof Person>;
  let instance: Instance = {
    name: '张三',
    getName() {}
  }
}

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

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

相关文章

Vue 和 React 前端框架的比较

Vue 和 React 前端框架的比较 本文研究了流行的前端框架 Vue 和 React 之间的区别。通过对它们的学习曲线、视图层处理方式、组件化开发、响应式数据处理方式和生态系统及社区支持进行比较分析&#xff0c;得出了它们在不同方面的优劣和特点。该研究对于开发者在选择合适的前端…

Ceph简介及部署

Ceph Ceph一、存储基础1、单机存储设备2、Ceph 简介3、Ceph 优势5、Ceph 架构6、Ceph 核心组件7、OSD 存储后端8、Ceph 数据的存储过程9、Ceph 版本发行生命周期10、Ceph 集群部署 二、部署ceph-deploy Ceph 集群前环境配置1、关闭 selinux 与防火墙2、根据规划设置主机名3、配…

Cisco学习笔记(CCNA)——Introduction to TCP/IP

Introduction to TCP/IP 常见协议 应用层协议 协议 端口号 描述 HTTP 80 超文本传输协议&#xff0c;提供浏览网页服务 Telnet 23 远程登录协议&#xff0c;提供远程管理服务 FTP 20、21 文件传输协议&#xff0c;提供互联网文件资源共享服务 SMTP 25 简单邮件传…

【Go语言开发】简单了解一下搜索引擎并用go写一个demo

写在前面 这篇文章我们一起来了解一下搜索引擎的原理&#xff0c;以及用go写一个小demo来体验一下搜索引擎。 简介 搜索引擎一般简化为三个步骤 爬虫&#xff1a;爬取数据源&#xff0c;用做搜索数据支持。索引&#xff1a;根据爬虫爬取到的数据进行索引的建立。排序&#xf…

LayUI之增删改查

目录 一、前言 1.1 前言 1.2 前端代码(数据表格组件) 1.3 封装JS 二、LayUI增删改查的后台代码 2.1 编写Dao方法 2.1 增加 2.2 删除 2.3 修改 三、LayUI增删改查的前端代码 3.1 增加 一、前言 1.1 前言 上一篇文章我们一起做了LayUI的动态添加选项卡&#xff0c;这一篇…

【天工Godwork精品教程】天工3.1.7安装教程(附Godwork完整版下载地址)

本文讲解天工3.1.7安装过程(附Godwork完整版网盘下载地址)。 文章目录 一、天工3.1.7安装教程1. 安装GodWork-AT 3.1.72. 安装GodWork-AT 3.1.7补丁3. 安装GodWork-EOS-Setup-2017B-12314. 安装GodWork-EOS补丁5. 运行godwokr软件6. 生成ZC码7. 输入ZC码8. eos插件调用二、天…

【大数据之Hadoop】三十七、Hadoop HA高可用

1、HA概述 实现高可用最关键的策略是消除单点故障。HA分成各个组件的HA机制&#xff1a;HDFS的HA和YARN的HA。   Hadoop2.0之前&#xff0c;在HDFS集群中NameNode存在单点故障&#xff08;SPOF&#xff09;。 NameNode主要在以下两个方面影响HDFS集群&#xff1a; &#xff…

07-尚硅谷大数据技术之Spark源码

1. 环境准备&#xff08;Yarn 集群&#xff09; 搭建Spark on Yarn集群 3.3 Yarn 模式 独立部署&#xff08;Standalone&#xff09;模式由 Spark 自身提供计算资源&#xff0c;无需其他框架提供资源。这种方式降低了和其他第三方资源框架的耦合性&#xff0c;独立性非常强。但…

PyTorch训练RNN, GRU, LSTM:手写数字识别

文章目录 pytorch 神经网络训练demoResult参考来源 pytorch 神经网络训练demo 数据集&#xff1a;MNIST 该数据集的内容是手写数字识别&#xff0c;其分为两部分&#xff0c;分别含有60000张训练图片和10000张测试图片 图片来源&#xff1a;https://tensornews.cn/mnist_intr…

每日一题2023.7.19|ACM模式

文章目录 C的输入方式介绍cin>>cin.get(字符变量名)cin.get(数组名,接收字符数目)cin.get()cin.getline() getline()gets()getchar() AB问题|AB问题||AB问题|||ABⅣAB问题ⅤAB问题Ⅵ C的输入方式介绍 参考博客 cin>> 最基本&#xff0c;最常用的字符或者数字的输…

TMS FlexCel for VCL FMX Crack

TMS FlexCel for VCL & FMX Crack 强大、广泛和灵活的组件套件&#xff0c;用于VCL和FireMonkey的本地Excel报告、文件生成和操作。 FlexCel for VCL/FireMonkey是一套允许操作Excel文件的Delphi组件。它包括一个广泛的API&#xff0c;允许本地读/写Excel文件。如果您需要在…

c#调用cpp库,debug时不进入cpp函数

选中c#的项目&#xff0c;右击属性&#xff0c;进入属性页&#xff0c;点击调试&#xff0c;点击打开调试启动配置文件UI&#xff0c;打开启用本机代码调试。

uniapp 集成七牛云,上传图片

1 创建项目 我是可视化创建项目的 &#xff0c;cli创建的项目可以直接使用npm安装七牛云。 2 拷贝qiniuUploader.js到项目&#xff0c;下面的回复 放了qiniuUploader.js百度云链接。 3 在需要使用qiniuUploader的vue文件 引入。 4 相册选择照片&#xff0c;或者拍照后&#xff…

工欲善其事,必先利其器之—react-native-debugger调试react native应用

调试react应用通常利用chrome的inspector的功能和两个最常用的扩展 1、React Developer Tools &#xff08;主要用于debug组件结构) 2、Redux DevTools &#xff08;主要用于debug redux store的数据&#xff09; 对于react native应用&#xff0c;我们一般就使用react-nativ…

vue 项目优化

去除冗余的css 消除框架中未使用的CSS,初步达到按需引入的效果 使用背景&#xff1a;vue2.x, webpack3.x 使用插件&#xff1a;purifycss-webpack 安装&#xff1a; npm i purifycss-webpack purify-css glob-all -D安装后各个插件的版本&#xff1a; “glob-all”: “^3.3.…

轻松实现数据一体化:轻易云数据集成平台全解析

在当今快速发展的商业环境中&#xff0c;企业面临着大量来自多样数据源的数据。如何将这些数据进行高效集成和利用&#xff0c;成为企业数字化转型的关键挑战。轻易云数据集成平台提供了一个一站式的解决方案&#xff0c;帮助企业实现数据的无缝集成和高效利用。下面我们将通过…

[java安全]URLDNS

文章目录 [java安全]URLDNS前言HashMapURLURLStreamHandler调用过程调用链流程图POC [java安全]URLDNS 前言 URLDNS利用链是一条很简单的链子&#xff0c;可以用来查看java反序列化是否存在反序列化漏洞&#xff0c;如果存在&#xff0c;就会触发dns查询请求 它有如下优点&a…

docker-compose搭建prometheus+grafana+钉钉告警

前言&#xff1a; 本文将介绍使用docker-compose部署搭建promtheus监控容器、主机、服务等相关状态&#xff1b; 配合granfana面板构建监控大屏&#xff1b; 由于grafana的报警不是很友好&#xff0c;使用dingtalk&#xff0c;配合altermanager&#xff0c;实现钉钉报警。 …

pico添加devmem2读写内存模块

devmem2读写内存 自定义msh命令devmem2验证msh命令devmem2读CPUID读写全局变量 devmem2模块可实现对设备寄存器的读写操作。在RT-Thread的命令行组件Fish中添加devmem2模块&#xff0c;用户可在终端输入devmem2相关命令&#xff0c;FinSH根据输入对指定寄存器进行读写&#xff…

提高LLaMA-7B的数学推理能力

概述 这篇文章探讨了利用多视角微调方法提高数学推理的泛化能力。数学推理在相对较小的语言模型中仍然是一个挑战&#xff0c;许多现有方法倾向于依赖庞大但效率低下的大语言模型进行知识蒸馏。研究人员提出了一种避免过度依赖大语言模型的新方法&#xff0c;该方法通过有效利…