ts的【不】常用技巧和工具函数归档

133 阅读2分钟

【不】常用小技巧

1.获取数组元素类型: type ArryType<T extends any[]> = T[number]
2.克隆数组: type CloneArr<T extends any[]> = { [k in keyof T]: T[k] }
3.推导数组产生类似as const作用: values: readonly [...T]
    declare function PromiseAll<T extends any[]>(values: readonly [...T]): Promise<{ [K in keyof T]: T[K] extends Promise<infer R> ? R : T[K] }>
4.字符串转换大写:使用内置的函数 Uppercase
5.判断是否是never:type IsNever<T> = [T] extends [never] ? true : false
 注意以下写法无法判断是否是never:
       
❌ type Test<T> = T extends never ? true : false
       
但是直接使用字面量是成立的:
       
✅ never extends never ? true : false 
6.判断是否为{} 空对象
  1. Record<string, never>
  2. type IsEmptyObj<T> = T extends Object ? keyof T extends never ? true : false : false
7.判断是否为联合类型

type IsUnion<T, U = T> = T extends U ? [U] extends [T]? false : true :never

8.判断是具体的字符而不是string的方法
  1. type IsStr<T> = T extends string ? string extends T ? false : true : false
  2. type IsStr<T> = T extends ${infer S} ? true : false
9.判断是否为纯数字字符串

type isNumberStr = T extends `${number}` ? true : false

10.快速复制对象:type cloneObj<T extends Record<any, any>> = Omit<T, nerver>
11.去除联合类型中的undefined: type RemoveUndefined<T> = [T] extends [undefined] ? T: Exclude<T, undefined>

常见知识点

  1. 泛型(T)如果是never,内部直接使用 T extends xx 会直接返回never

常用工具函数

1. 设置对象所有值为never
    
type SetKeyNever<T, K extends keyof T> = {
  [x in K]?: never;
};

2.多个属性相互互斥
        
/**
 * 多个属性相互互斥
 */
export type JustOne<T, K extends (keyof T)[] = [], Y extends keyof T = K[number]> = NonNullable<
  {
    [x in Y]: Pick<T, Exclude<keyof T, Exclude<Y, x>>> & SetKeyNever<T, Exclude<Y, x>>;
  }[Y]
>;

3.联合类型转交叉
/**
 * 联合类型转交叉
 */
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
  k: infer I,
) => void
  ? I
  : never;
4.首字母大写

/**
 * 首字母大写
 */
export type FirstLetterUppercase<T extends string> = T extends `${infer F}${infer A}`
  ? `${Uppercase<F>}${A}`
  : T;

5.删除末尾字符

/**
 * 删除末尾字符
 * 1.serach last
 * 2.string to tuple and delete last item
 */
export type DeleteLastLetter<
  T extends string,
  O extends string = '',
> = T extends `${infer F}${infer R}` ? (R extends '' ? O : DeleteLastLetter<R, `${O}${F}`>) : O;

4.获取对象所有的key的完整路径

/**
 * 获取对象所有的key的完整路径
 * {user: {name: string, age: number}, title: string} ===> 'user.name' | 'user.age' | 'title'
 */
type PickString<T> = T extends string ? T : never;
export type GetObjFullPaths<T extends Record<string, any>> = PickString<
  | keyof {
      [k in keyof T as T[k] extends Record<string, any> ? never : k]: 1;
    }
  | keyof {
      [k in keyof T as k extends string
        ? T[k] extends Record<string, any>
          ? `${k}.${GetObjFullPaths<T[k]>}`
          : never
        : never]: 1;
    }
>;