Typescript
类型体操
1. 某个类型前面直接加good_前缀
type AppendGood<T> = {
[P in keyof T as `good_${string & P}`]: T[P];
}2. 把横线命名的字符串类名转化为驼峰命名 CamelCase
export type CamelCase<S extends string> =
S extends `${infer Head}-${infer Rest}`
? `${Lowercase<Head>}${CamelCase<Capitalize<Rest>>}`
: S
type A = 'list-change'
type B = CamelCase<A> // ==> listChange3. 对象合并
export type Merge<A, B> = {
[K in keyof (A & B)]: K extends keyof B
? B[K]
: K extends keyof A
? A[K]
: never
}4. 点点获取对象的key
type Primitive = string | boolean | number | bigint | symbol | undefined | null
type DeepKeys<T, P extends string | number | symbol = ''> = {
[K in keyof T]-?: T[K] extends Primitive
? `${P extends '' ? '' : `${P & string}.`}${K & string}`
: `${P extends '' ? '' : `${P & string}.`}${K & string}` | DeepKeys<T[K], `${P & string}.${K & string}`>
}[keyof T]
interface Data {
foo: {
bar: {
value: 'foobar'
}
count: 6
included: true
}
hello: 'world'
}
type Keys = DeepKeys<Data>5. Merge类型
type Merge<A, B> = {
[K in keyof (A & B)]: K extends keyof B
? B[K]
: K extends keyof A
? A[K]
: never
}6. 指定某一个属性为必选参数
type MakeOptionalPropertyRequired<T, K extends keyof T> = T & Required<Pick<T, K>>7. 去除undefined
type WithoutUndefined<T> = T extends undefined ? never : T8. 去除 readonly
type RemoveReadonly<T> = {
-readonly [K in keyof T]: T[K];
}9. 类型
三个ts中的类型
type c = string
type d = c[]
type e = number[]我期望把type e 改为一个泛型,接受d,然后e的每一项都是d的每一项字符串的长度。
type c = string
type d = c[]
type e<T extends string[]> = {
[K in keyof T]: T[K]['length'];
}
// 示例用法
const exampleArray: d = ['apple', 'banana', 'orange']
const result: e<d> = [5, 6, 6] // e<d> 的每一项都是 d 中每一项字符串的长度10. 获取函数key
type GetFunctionKeys<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => any ? K : never
}[keyof T]
type Fn = GetFunctionKeys<{
done: () => void
msg: () => void
name: void
}> // ===> 'done' | 'msg'11. 获取函数名称
type FunctionKeys<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
}[keyof T]12. 相等判断
type IsEqual<X, Y> =
(<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2)
? true
: false分解每个部分:
<T>() 是一个泛型函数声明T extends X ? 1 : 2是条件类型检查- 整体使用
extends比较两个函数类型是否相同
这种实现的巧妙之处在于:
- 当
X和Y完全相同时,两个函数类型会生成完全相同的条件类型 - 如果
X和Y有任何差异(比如一个有 readonly,另一个没有),生成的条件类型就会不同
interface A { a: string }
interface B { readonly a: string }
// 以下两个类型是不同的:
type Func1 = <T>() => T extends A ? 1 : 2 // (可能返回 1 或 2)
type Func2 = <T>() => T extends B ? 1 : 2 // (可能返回 1 或 2)这样做更准确:
- 普通的
X extends Y在处理结构类似但修饰符不同的类型时可能会给出错误的结果 - 使用函数类型包装可以捕获到更细微的类型差异
- 泛型参数
T在这里起到了"探测器"的作用,帮助我们识别类型的完整结构