TS珠峰 004【学习笔记】

类型体操

type-1

// 内置
// Partial Required Readonly 修饰类型的
// Pick Omit 处理数据结构
// Exclude Extract 处理集合类型的
// Paramters RetrunValue infer
// 字符串类型,模板字符串`${}` + infer

PartialPropsOptional

// 1. Partial
// 2. Optional
// 3. Readonly
// 4. Pick
// 5. Omit

// Partial
// 将对象的属性变为可选的

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

type PartialPropsOptional<T extends Object, K extends keyof T> = Partial<
  Pick<T, K>
> &
  Omit<T, K>;

type Computed<T> = {
  [K in keyof T]: T[K];
};

type p1 = Computed<PartialPropsOptional<Person, 'age' | 'address'>>;

export {};

ExtractKeysByValueType

// 如何通过值类型拿到key
//将类型相同的进映射{name:"name",age:"never",address:"address"}
// name | never | address --> name | address
// 如何判断两个类型是否相同
type isEqual<T, U> = T extends U ? (U extends T ? true : false) : false;

type PickKeysByValue<T, V> = {
  // [K in keyof T]: T[K] extends V ? K : never;
  [K in keyof T]: isEqual<T[K], V> extends true ? K : never;
}[keyof T];

type OmitKeysByValue<T, V> = {
  [K in keyof T]: isEqual<T[K], V> extends true ? never : K;
}[keyof T];

type p2 = Computed<PickKeysByValue<Person, string>>; // 应该拿到name address
type p3 = Computed<OmitKeysByValue<Person, string>>; // 应该拿到age

// 模板字符串,里面有一个很重要的功能,重映射
type PickKeysByValue2<T, U> = {
  // 直接将对象的属性就给忽略掉了
  // 循环对象的key,看值的类型是否相同,如果相同留下这个key
  [K in keyof T as T[K] extends U ? K : never]: T[K];
};

type p4 = PickKeysByValue2<Person, string>;

export {};

OrType.ts

// 子类型互斥 OrType.ts
interface Man1 {
  fortune: string;
}
interface Man2 {
  funny: string;
}
interface Man3 {
  foreign: string;
}

type ManType = Man1 | Man2 | Man3; // 希望ManType只是其中的一种类型
let man: ManType = {
  fortune: '富有',
  funny: '风趣',
  foreign: '洋派',
}; // 希望ManType只是其中的一种类型
// man1-man2 将man1的属性标记成never +man2
// man2-man1 将man2的属性标记成never +man1
type DiscardType<T, U> = {
  [K in Exclude<keyof T, keyof U>]?: never;
};
type OrType<T, U> = (DiscardType<T, U> & U) | (DiscardType<U, T> & T);
type manType2 = OrType<Man3, OrType<Man1, Man2>>;
let man2: manType2 = {
  fortune: '富有',
};

export {};

交 差 并 补

// 对象的 交差并补
type A = {
  name: string;
  age: number;
  address: string;
};

type B = {
  name: string;
  male: boolean;
  address: number;
};

// 交集
type ObjIntersect<T extends object, U extends object> = Pick<
  T,
  Extract<keyof T, keyof U>
>;
type p1 = ObjIntersect<A, B>;

// 差集
type ObjectDiff<T extends object, U extends object> = Pick<
  T,
  Exclude<keyof T, keyof U>
>;
type R2 = ObjectDiff<A, B>;

// 补集 就是差集,要求是有父子关系
type ObjectCom<T extends U, U extends object> = Pick<
  T,
  Exclude<keyof T, keyof U>
>;
// type R3 = ObjectCom<B,A>

// 重写 以后面的类型为准 再加上以前比现在多的类型
type Overwrite<T extends object, U extends object> = ObjIntersect<U, T> &
  ObjectDiff<T, U>;
type Computed<T> = {
  [K in keyof T]: T[K];
} & {};
type R4 = Computed<Overwrite<A, B>>;
export {};

infer

// 模式匹配类型,抢断函数类型中参数的最后一个参数类型
function sum(a: string, b: string, c: number) {}
type LastParam<T extends (...args: any[]) => any> = T extends (
  ...args: infer P
) => any
  ? P extends [...any[], infer L]
    ? L
    : never
  : never;
type X = LastParam<typeof sum>;
export {};

type-2

首字母大写

// 首字母大写
// export type CapitalizeString<T> = T extends string
//   ? `${Capitalize<T & string>}`
//   : T;
// 默认情况,字符串的infer只匹配第一个字符
// 针对字符的infer 默认infer第一个指代的是第一个字符,后面的就是所有的
// 如果有分隔符号,指代的就是分隔符之前的
export type CapitalizeString<T> = T extends `${infer First}${infer Rest}`
  ? `${Capitalize<First>}${Rest}`
  : T;
type a1 = CapitalizeString<'handler'>;
type a2 = CapitalizeString<'parent'>;
type a3 = CapitalizeString<223>;

export {};

FirstChar

// 获取字符串的字面量中的第一个字符
type FirstChar<T extends string> = T extends `${infer L}${infer R}` ? L : T;
type A = FirstChar<'BFE'>; // B
type B = FirstChar<'dev'>; // BFE
type C = FirstChar<'234'>; // 234

LastChar

// lastchar
type LastChar<T, F = never> = T extends `${infer L}${infer R}` ? LastChar<R, L> : F;
type A1 = LastChar<'BFE'>; // E
type B1 = LastChar<'dev'>; // v
type C1 = LastChar<'234'>; // 4

字符串转元组

// string toTuple(元组)
type StringToTuple<T extends string> = T extends `${infer L}${infer R}` ? [L, ...StringToTuple<R>] : [];
type A2 = StringToTuple<'BFE'>; // ['B', 'F', 'E']
type B2 = StringToTuple<'dev'>; // ['d', 'e', 'v']
type C2 = StringToTuple<'234'>; // ['2', '3', '4']

元组转成字符串

// 元组转字符串
type TupleToString<T extends string[]> = T extends [infer L, ...infer R] ? `${L}${TupleToString<R>}` : '';
type A3 = TupleToString<['B', 'F', 'E']>; // 'BFE'
type B3 = TupleToString<['d', 'e', 'v']>; // 'dev'
type C3 = TupleToString<['2', '3', '4']>; // '234'

重复字符串

// repeat string
type RepeatString<
  T extends string,
  C extends number,
  A extends any[],
  F extends string = ''
> = C extends A['length'] ? F : RepeatString<T, C, [...A, any], `${F}${T}`>;
type A4 = RepeatString<'a', 3, [], ''>; // 'aaa'
type B4 = RepeatString<'a', 0, [], ''>; // ''
type C4 = RepeatString<'a', -1, [], ''>; // ''

split string 根据infer的左右分割,在左边放到数组中,右边递归,最终在结果集中增加无法匹配的即可

type SplitString<
  T extends string,
  S extends string,
  A extends any[]
> = T extends `${infer L}${S}${infer R}`
  ? SplitString<R, S, [L, ...A]>
  : [...A, T];
type A5 = SplitString<'handle-open-flag', '-', []>; // ['handle', 'open', 'flag']
type B5 = SplitString<'open-flag', '-', []>; // ['open', 'flag']
type C5 = SplitString<'BFE.dev.fe.js', '.', []>; // ['BFE', 'dev', 'fe', 'js']
type D5 = SplitString<'BFE.dev.fe.js', '-', []>; // ['BFE.dev.fe.js']

计算字符串长度

// 计算字符串字面量的长度
type StringLength<
  T extends string,
  A extends any[]
> = T extends `${infer L}${infer R}` ? StringLength<R, [L, ...A]> : A['length'];
type A6 = StringLength<'BFE.dev', []>; // 7
type B6 = StringLength<'dev', []>; // 3
type C6 = StringLength<'', []>; // 0

驼峰转连接符

// 驼峰命名转横杠命名
// 如何匹配大写? Capitalize<H> extends H
// 把大写变成--> -小写
type RemoveFirstLetter<T extends string> = T extends `-${infer V}` ? V : T;
type KebabCase<
  T extends string,
  F extends string = ''
> = T extends `${infer L}${infer R}`
  ? L extends Capitalize<L>
    ? KebabCase<R, `${F}-${Lowercase<L>}`>
    : KebabCase<R, `${F}${L}`>
  : RemoveFirstLetter<F>;
type aa1 = KebabCase<'HandleOpenFlag'>; // handle-open-flag
type aa2 = KebabCase<'OpenFlag'>; // open-flag

横杠命名转为驼峰命名

// 横杠命名转驼峰命名
type CamelCase<
  T extends string,
  F extends string = ''
> = T extends `${infer L}-${infer R1}${infer R2}`
  ? CamelCase<R2, `${F}${L}${Capitalize<R1>}`>
  : Capitalize<`${F}${T}`>;

type Bb1 = CamelCase<'handle-open-flag', ''>; // HandleOpenFlag
type Bb2 = CamelCase<'open-flag', ''>; // OpenFlag

object-->path

export type ObjectAccessPaths<
  T,
  F extends string = '',
  K = keyof T
> = K extends keyof T
  ? T[K] extends object
    ? // 如果当前的值是对象继续递归拼接,并且将当前解析的key 拼接到结果集中
      ObjectAccessPaths<T[K], `${F}${K & string}.`>
    : `${F}${K & string}` // 这里会丢失不是对象的最后一个key,
  : never;

function createI18n<Schema>(
  schema: Schema
): (path: ObjectAccessPaths<Schema>) => void {
  return (key: string) => {};
}

const i18n = createI18n({
  home: {
    topBar: {
      title: '首页',
      welcome: '欢迎来到首页',
    },
    bottomBar: {
      notes: '笔记',
    },
  },
  login: {
    title: '登录',
    username: '用户名',
    password: '密码',
    login: '登录',
  },
});
i18n('home.topBar.title');
// i18n('home.topBar.title');
i18n('home.bottomBar.notes');
i18n('login.title');
i18n('login.username');
i18n('login.password');
i18n('login.login');
i18n('login.xxx'); // 报错了

判断传入的字符串字面量类型中是否含有某个字符串

// 判断传入的字符串字面量类型中是否含有某个字符串
type Includes<
  T extends string,
  S extends string
> = T extends `${infer L}${S}${infer R}` ? true : false;
type a1 = Includes<'hello', 'h'>; // true
type a2 = Includes<'hello', 'e'>; // true
type a3 = Includes<'hello', 'a'>; // false
type a4 = Includes<'', ''>; //true T extends "" && S extends ""

trim 删除两边的空格

// trim
type TrimLeft<T extends string> = T extends ` ${infer R}` ? TrimLeft<R> : T;
type TrimRight<T extends string> = T extends `${infer R} ` ? TrimRight<R> : T;
type Trim<T extends string> = TrimRight<TrimLeft<T>>;
type a5 = Trim<'  .hello  '>; // '.hello'

replace

// 构建一个查找规则,找到后将左边和右边留起来${infer L}${S}${infer R}

type Replace<
  S extends string,
  From extends string,
  To extends string
> = From extends ''
  ? S
  : S extends `${infer L}${From}${infer R}`
  ? `${L}${To}${Replace<R, From, To>}`
  : S;

type aa1 = Replace<'hello world', 'world', 'walker'>; // 'hello walker'
type bb1 = Replace<'jwjw', 'jw', 'jiangwen'>; // 'jiangwenjiangwen'
type bb2 = Replace<'ha ha ha', 'ha', 'he'>; // 'he he he'
type aa2 = Replace<'jw', 'jw', 'jiangwen'>; // 'jiangwen'
type aa3 = Replace<'a', '', 'jiangwen'>; // 'jiangwenjiangwen'


type Replace1<T extends string,C extends string,RC extends string,F extends string = "">=
C extends ""? T extends ""?RC: `${RC}${T}`:T extends `${infer L}${C}${infer R}`? Replace1<R,C,RC,`${F}${L}${RC}`>:`${F}${T}`
type t1 = Replace1<"ha ha ha","ha","he">
type t2 = Replace1<"jw","jw","jiangwen">
type t3 = Replace1<"a","","jiangwen">
type t4 = Replace1<"","","jiangwen">
// 定义组件的监听事件类型
type EventType = {
  'handle-open': (flage: boolean) => true;
  'preview-item': (data: { item: any; index: number }) => true;
  'close-item': (data: { item: any; index: number }) => true;
};
/*
{
 onHandleOpen: (flage: boolean) => true;
 onPreviewItem: (data: { item: any; index: number }) => true;
 onCloseItem: (data: { item: any; index: number }) => true;
}
*/
// 实现type2
type ComponentEmitsType<T> = {
  [K in keyof T as `on${Capitalize<K>}`]: T[K] extends (...args: infer P) => any?(...args:P)=>void;
};
type EventType2 = ComponentEmitsType<EventType>;
// 转化为类型

元组的操作

// 计算元组类型的长度
type LengthOfTuple<T extends any[]> = T extends { length: infer L } ? L : never;
type A = LengthOfTuple<[1, 2, 3, 4, 5]>;
type B = LengthOfTuple<[]>;

// 元组第一项
type FirstItem<T extends any[]> = T extends [infer F, ...infer R] ? F : never;
type C = FirstItem<[1, 2, 3, 4, 5]>;
type D = FirstItem<[]>;

// 元组最后一项
type LastItem<T extends any[]> = T extends [...infer R, infer L] ? L : never;
type E = LastItem<[1, 2, 3, 4, 5]>;

// 移除元组第一项
type RemoveFirstItem<T extends any[]> = T extends [infer F, ...infer R]
  ? R
  : never;
type F = RemoveFirstItem<[1, 2, 3, 4, 5]>;
type G = RemoveFirstItem<[]>;

// 移除元组最后一项
type RemoveLastItem<T extends any[]> = T extends [...infer R, infer L]
  ? R
  : never;
type I = RemoveLastItem<[1, 2, 3, 4, 5]>;
type J = RemoveLastItem<[]>;

// push
type Push<T extends any[], V> = [...T, V];
type H = Push<[1, 2, 3, 4, 5], 6>;

// 反转元组 反转链表
type ReverseTuple<T extends any[]> = T extends [infer F, ...infer R]
  ? [...ReverseTuple<R>, F]
  : T;
type K = ReverseTuple<[1, 2, 3, 4, 5]>;
type L = ReverseTuple<[string, number, boolean]>;
type M = ReverseTuple<[]>;

// flatten 扁平化
type Flatten<T extends any[]> = T extends [infer F, ...infer R]
  ? [...(F extends any[] ? Flatten<F> : [F]), ...Flatten<R>]
  : T;
type N = Flatten<[1, [2, [3, [4, [5]]]]]>;
type O = Flatten<[[1, 2], [3, 4], [5, 6]]>;
type P = Flatten<[1]>;
type Q = Flatten<[]>;

// repeat
type Repeat<T, C extends number, F extends any[] = []> = C extends F['length']
  ? F
  : Repeat<T, C, [...F, T]>;
type A1 = Repeat<number, 3>; //[number,number,number]
type A2 = Repeat<string, 2>; //[string,string]
type A3 = Repeat<boolean, 1>; //[boolean]

// 过滤指定类型
type Filter<T extends any[], U, F extends any[] = []> = T extends [
  infer L,
  ...infer R
]
  ? // 如果需要则放到数组里,不需要返回原来
    Filter<R, U, [L] extends [U] ? [...F, L] : F>
  : F;
type A4 = Filter<[1, 'BEF', 2, true, 'dev'], number>; // [1,2]
type A5 = Filter<[1, 'BEF', 2, true, 'dev'], string>; // ["BEF","dev"]
type A6 = Filter<[1, 'BEF', 2, true, 'dev'], boolean>; // [true]
type A7 = Filter<[1, 'BEF', 2, any, 'dev'], string>; // ["BFE",any,'dev']

// FindIndex
type IsEqual<A, B, Success, Faile> = [A] extends [B]
  ? [B] extends [A]
    ? keyof A extends keyof B
      ? keyof B extends keyof A
        ? Success
        : Faile
      : Faile
    : Faile
  : Faile;
type FindIndex<T extends any[], U, F extends any[] = []> = T extends [
  infer L,
  ...infer R
]
  ? IsEqual<L, U, F['length'], FindIndex<R, U, [...F, L]>>
  : never;

type A8 = [any, never, 1, '2', true];
type A9 = FindIndex<A8, 1>; // 2
type A10 = FindIndex<A8, 3>; // never
type A11 = FindIndex<A8, true>; // 4
type A12 = FindIndex<A8, string>; // never

// 元组转成枚举,枚举对象中的值就是元素中某个元素中某个类型的字面量类型
type a1 = TupleToEnum<['MacOS', 'Windows', 'Linux']>;
// {readonly MacOS: "MacOS"; readonly Windows: "Windows"; readonly Linux: "Linux"}
// 如果传递了第二个参数为true,则枚举对象中值的类型是元素在元组中的index索引
type a2 = TupleToEnum<['MacOS', 'Windows', 'Linux'], true>;
// {readonly MacOS: 0; readonly Windows: 1; readonly Linux: 2}

type TupleToEnum<T extends any[], I extends boolean = false> = {
  readonly [K in T[number]]: IsEqual<I, true, FindIndex<T, K>, K>;
};

// slice
// 如果没有达到开头的长度,就要记录找到了多少个元素
type Slice<
  T extends any[],
  S extends number,
  E extends number = T['length'],
  SA extends any[] = [],
  SE extends any[] = [],
  F extends any[] = []
> = T extends [infer L, ...infer R]
  ? SA['length'] extends S
    ? SE['length'] extends E
      ? [...F, L]
      : Slice<R, S, E, SA, [...SE, null], [...F, L]>
    : Slice<R, S, E, [...SA, null], [...SE, null], F>
  : F;

type S1 = Slice<[any, never, 1, '2', true, boolean], 0, 2>; // [any,never,1]
type S2 = Slice<[any, never, 1, '2', true, boolean], 1, 3>; // [never,1,'2']
type S3 = Slice<[any, never, 1, '2', true, boolean], 1, 2>; // [never,1]
type S4 = Slice<[any, never, 1, '2', true, boolean], 2>; // [1,'2',true,boolean]
type S5 = Slice<[any], 2>; // []
type S6 = Slice<[], 0>; // []

// splice 删除并替换元素
type Splice<
  Arr extends any[],
  Start extends number,
  Count extends number = 0,
  Replace extends any[] = [],
  StartCount extends any[] = [],
  CountArr extends any[] = [],
  Result extends any[] = []
> = StartCount['length'] extends Start
  ? CountArr['length'] extends Count
    ? [...Result, ...Replace, ...Arr]
    : Arr extends [infer First, ...infer Rest]
    ? Splice<Rest, Start, Count, Replace, StartCount, [...CountArr, 0], Result>
    : Result
  : Arr extends [infer First, ...infer Rest]
  ? Splice<
      Rest,
      Start,
      Count,
      Replace,
      [...StartCount, 0],
      CountArr,
      [...Result, First]
    >
  : Result;

type SP1 = Splice<[string, number, boolean, null, undefined, never], 0, 2>; // [boolean,null,undefined,never]
type SP2 = Splice<[string, number, boolean, null, undefined, never], 1, 3>; // [string,undefined,never]
type SP3 = Splice<
  [string, number, boolean, null, undefined, never],
  1,
  2,
  [1, 2, 3]
>; // [string,1,2,3,null,undefined,never]

export {};

类型操作

// 获取对象类型中的可选属性的联合类型
// @ts-nocheck
type OptionalKeys<T> = keyof {
  [K in keyof T as T[K] extends Required<T>[K] ? never : K]: T[K];
};

type a1 = OptionalKeys<{
  foo: number | undefined;
  bar?: string;
  flag: boolean;
}>; // bar

type a2 = OptionalKeys<{ foo: number; bar?: string }>; // bar

type a3 = OptionalKeys<{ foo: number; flag: boolean }>; // never

type a4 = OptionalKeys<{ foo?: number; flag?: boolean }>; // foo|flag

type a5 = OptionalKeys<{}>; // never

// 获取对象类型中的必选属性
type PickRequired<T> = {
  [K in keyof T as T[K] extends Required<T>[K] ? K : never]: T[K];
};

type p1 = PickRequired<{
  foo: number | undefined;
  bar?: string;
  flag: boolean;
}>; // {foo:number|undefined, flag:boolean}

type p2 = PickRequired<{ foo: number; bar?: string }>; // {foo:number}

type p3 = PickRequired<{ foo: number; flag: boolean }>; // {foo:number,flag:boolean}

type p4 = PickRequired<{ foo?: number; flag?: boolean }>; // {}

type p5 = PickRequired<{}>; // {}

// 判断类型是否是 never
type IsNever<T> = [T] extends [never] ? true : false;

type A = IsNever<never>; // true
type B = IsNever<string>; // false
type C = IsNever<undefined>; // false
type D = IsNever<any>; // false

// 判断是否为没有属性的对象类型 {}
// @ts-nocheck
type x1 = keyof {}; // never

type IsEmptyType<T> = T extends object
  ? keyof T extends never
    ? true
    : false
  : false;

type EA = IsEmptyType<string>; // false
type EB = IsEmptyType<{ a: 3 }>; // false
type EC = IsEmptyType<{}>; // true
type ED = IsEmptyType<any>; // false
type EE = IsEmptyType<object>; // false
type EF = IsEmptyType<Object>; // false
type EG = IsEmptyType<unknown>; // false

// 判断类型是否是 any
// 可以将 unknown 赋予给 any
type IsAny<T> = unknown extends T ? true : false;

type IA = IsAny<string>; // false
type IB = IsAny<any>; // true
type IC = IsAny<unknown>; // false
type ID = IsAny<never>; // false

// @ts-nocheck
interface Action<T> {
  payload?: T;
  type: string;
}

interface Module {
  count: number;
  message: string;
  asyncMethod<T, U>(input: Promise<T>): Promise<Action<U>>;
  syncMethod<T, U>(action: Action<T>): Action<U>;
}

// 这个要求的结果
type Result = {
  asyncMethod<T, U>(input: T): Action<U>;
  syncMethod<T, U>(action: T): Action<U>;
};

type Connect<T> = {
  [K in keyof T]: T[K] extends (
    input: Promise<infer A>
  ) => Promise<Action<infer B>>
    ? (input: A) => Action<B>
    : T[K] extends (action: Action<infer A>) => Action<infer B>
    ? (action: A) => Action<B>
    : T[K];
};

type F = Connect<Module>;

// 将联合类型转换为交叉类型
// @ts-nocheck
type UnionToIntersection<U> = (
  U extends any ? (arg: U) => any : never
) extends (arg: infer I) => any
  ? I
  : never;

type UA = UnionToIntersection<{ a: string } | { b: string } | { c: string }>; // {a: string} & {b: string} & {c: string}

// 联合类型转换为元组类型
// @ts-nocheck
type UnionToTuple<T> = UnionToIntersection<
  T extends any ? (t: T) => T : never
> extends (_: any) => infer W
  ? [...UnionToTuple<Exclude<T, W>>, W]
  : [];

type a1 = UnionToTuple<1 | 2 | 3>; // [1,2,3]
type a2 = UnionToTuple<1 | 2 | boolean | string>; // [1,2,boolean,string]

export {};

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/4412

(0)
Walker的头像Walker
上一篇 2026年3月10日 00:00
下一篇 2026年3月8日 15:40

相关推荐

  • Go工程师体系课 004【学习笔记】

    需求分析 后台管理系统 商品管理 商品列表 商品分类 品牌管理 品牌分类 订单管理 订单列表 用户信息管理 用户列表 用户地址 用户留言 轮播图管理 电商系统 登录页面 首页 商品搜索 商品分类导航 轮播图展示 推荐商品展示 商品详情页 商品图片展示 商品描述 商品规格选择 加入购物车 购物车 商品列表 数量调整 删除商品 结算功能 用户中心 订单中心 我的…

    2025年11月25日
    27700
  • Go工程师体系课 017【学习笔记】

    限流、熔断与降级入门(含 Sentinel 实战) 结合课件第 3 章(3-1 ~ 3-9)的视频要点,整理一套面向初学者的服务保护指南,帮助理解“为什么需要限流、熔断和降级”,以及如何用 Sentinel 快速上手。 学习路线速览 3-1 理解服务雪崩与限流、熔断、降级的背景 3-2 Sentinel 与 Hystrix 对比,明确技术选型 3-3 Sen…

    个人 2025年11月25日
    24200
  • Go工程师体系课 012【学习笔记】

    Go 中集成 Elasticsearch 1. 客户端库选择 1.1 主流 Go ES 客户端 olivere/elastic:功能最全面,API 设计优雅,支持 ES 7.x/8.x elastic/go-elasticsearch:官方客户端,轻量级,更接近原生 REST API go-elasticsearch/elasticsearch:社区维护的官…

    个人 2025年11月25日
    28100
  • 深入理解ES6 005【学习笔记】

    解构:使用数据访问更便捷 如果使用var、let或const解构声明变量,则必须要提供初始化程序(也就是等号右侧的值)如下会导致错误 // 语法错误 var {tyep,name} // 语法错误 let {type,name} // 语法错误 const {type,name} 使用解构给已经声明的变量赋值,哪下 let node = { type:&qu…

    个人 2025年3月8日
    1.3K00
  • Go工程师体系课 protoc-gen-validate【学习笔记】

    protoc-gen-validate 简介与使用指南 ✅ 什么是 protoc-gen-validate protoc-gen-validate(简称 PGV)是一个 Protocol Buffers 插件,用于在生成的 Go 代码中添加结构体字段的验证逻辑。 它通过在 .proto 文件中添加 validate 规则,自动为每个字段生成验证代码,避免你手…

    个人 2025年11月25日
    1.4K00
简体中文 繁体中文 English