类型体操
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://joyjs.cn/archives/4412