TS Everest 004 [Learning Notes]

Type manipulation type-1 // Built-in // Partial, Required, Readonly for modifying types // Pick, Omit for manipulating data structures // Exclude, Extract for manipulating union types // Parameters, ReturnType, infer // String types, template literal types `${}` + infer, PartialPropsOptional ...

Type Challenges

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 {};

Intersection, Difference, Union, Complement

// 对象的 交差并补
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

Capitalize First Letter

// 首字母大写
// 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 to Tuple

// 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']

Tuple to String

// 元组转字符串
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

// 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: split by infer's left and right, put the left part into an array, recurse on the right part, and finally add any unmatched parts to the result set.

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']

Calculate String Length

// 计算字符串字面量的长度
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

CamelCase to KebabCase

// 驼峰命名转横杠命名
// 如何匹配大写? 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

KebabCase to CamelCase

// 横杠命名转驼峰命名
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 to 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: 'Home',
      welcome: '欢迎来到Home',
    },
    bottomBar: {
      notes: '笔记',
    },
  },
  login: {
    title: 'Login',
    username: '用户名',
    password: '密码',
    login: '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'); // 报错了

Check if a string literal type contains a specific string.

// 判断传入的字符串字面量类型中是否含有某个字符串
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: remove whitespace from both ends.

// 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>;
// 转化为类型

Tuple Operations

// 计算元组类型的长度
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 {};

Type Operations

// 获取对象类型中的可选属性的联合类型
// @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://www.walker-learn.xyz/archives/4412

(0)
Walker的头像Walker
上一篇 Mar 27, 2025 15:01
下一篇 Apr 6, 2025 22:23

Related Posts

  • Go Engineer Training Course 018 [Learning Notes]

    Getting Started with API Gateway and Continuous Deployment (Kong & Jenkins) corresponds to the course materials "Chapter 2: Getting Started with Jenkins" and "Chapter 3: Deploying Services with Jenkins", outlining the practical path for Kong and Jenkins in enterprise-level continuous delivery. Even with zero prior experience, you can follow the steps to build your own gateway + continuous deployment pipeline. Pre-class Introduction: What is an API Gateway? An API Gateway sits between clients and backend microservices...

    Personal Nov 25, 2025
    26300
  • In-depth Understanding of ES6 002 [Study Notes]

    Strings and Regular Expressions. Strings and Regular Expressions. JavaScript strings have always been built based on 16-bit character encoding (UTF-16). Each 16-bit sequence is a code unit, representing a character. String properties and methods like `length` and `charAt()` are all constructed based on these code units. The goal of Unicode is to provide a globally unique identifier for every character in the world. If we limit the character length to 16 bits, the number of code points will not...

    Personal Mar 8, 2025
    2.0K00
  • Go Engineer Comprehensive Course: protoc-gen-validate Study Notes

    protoc-gen-validate: Introduction and Usage Guide ✅ What is protoc-gen-validate? protoc-gen-validate (PGV for short) is a Protocol Buffers plugin used to add validation logic for struct fields in generated Go code. It automatically generates validation code for each field by adding validation rules in .proto files, saving you the trouble of manually...

    Personal Nov 25, 2025
    1.4K00
  • From 0 to 1: Implementing Micro-frontend Architecture 001 [Study Notes]

    Micro-frontends, JS isolation, CSS isolation, element isolation, lifecycle, preloading, data communication, application navigation, multi-level nesting. Note: This uses Mermaid's flowchart syntax, which is supported by Markdown renderers such as Typora, VitePress, and some Git platforms. Retained: Host application main-vue3; child applications: child-nuxt2-home, child-vue2-job, child-vu...

    Apr 20, 2025
    1.6K00
  • Go Engineer Systematic Course 008 [Study Notes]

    Orders and Shopping Cart
    First, copy the service code framework of 'srv' from the inventory service, then find and replace the corresponding name (order_srv).

    Fundamentals of Encryption Technology
    Symmetric Encryption
    Principle:
    Uses the same key for encryption and decryption.
    Like a single key that can both lock and unlock a door.
    Fast encryption speed, suitable for large data transfers.
    Use cases:
    Local file encryption
    Database content encryption
    Content encryption during large data transfers
    Fast communication between internal systems...

    Personal Nov 25, 2025
    27900
EN
简体中文 繁體中文 English