Skip to content

ts 类型

协变和逆变的区别,如果你不理解或没听说过这两个词,建议你记住结论就行了:infer类型推导,函数参数的位置是交叉类型,其他位置都是联合类型。

获取对象全部路径(包含深度路径)

这个类型定义中,通过 [K in keyof T]``,遍历了 T对象中的每个属性K,然后通过 K extends string ?来判断K是否为字符串类型,如果是,则继续判断T[K]是否是一个嵌套的对象类型,如果是,则返回K.{K}.K.{Path<T[K]>},这里使用了递归调用 Path<T[K]>来处理多层嵌套属性。如果T[K]不是嵌套的对象类型,则返回属性名K。如果 K不是字符串类型,则返回never`。

typescript
type Path<T> = {
    [K in keyof T]: K extends string
        ? T[K] extends Record<string, any>
            ? `${K}.${Path<T[K]>}`
            : K
        : never
}[keyof T]

interface IConfig {
    host: string
    port: string
    db: {
        host: string
        port: number
    }
}

type IConifgPath = Path<IConfig> // "host" | "port" | "db.host" | "db.port"

联合类型转 tuple

ts
type UnionToIntersection<T> = (T extends infer R ? (fn: () => R) => void : never) extends (
    a: infer S
) => void
    ? S
    : never
type IntersectionLast<T> = T extends () => infer R ? R : never
type UnionLast<T> = IntersectionLast<UnionToIntersection<T>>

type UnionToTuple<T, R extends Array<unknown> = [], L = UnionLast<T>> = [T] extends [never]
    ? R
    : UnionToTuple<Exclude<T, L>, [...R, L]>

UnionToTuple<'a' | 'b'> // ['a', 'b']

柯里化

typescript
type Curried<A, R> = A extends []
    ? () => R
    : A extends [infer ARG]
      ? (params: ARG) => R
      : A extends [infer ARG, ...REST]
        ? (params: ARG) => Curried<REST, R>
        : never

declare function curry<A extends any[], R>(fn: (...args: A) => R): Curried<A, R>

全局类型定义

jquery

declare const $: any

注意该声明所在文件应该被 tsconfig.json include

具名导出
ts
// types.d.ts
declare module 'my-library' {
    export function myFunction(param: string): number
    export const myConstant: string
    export interface MyInterface {
        prop1: string
        prop2: number
    }
}
npm 依赖
ts
declare module 'eslint-plugin-react-hooks' {
    const hooks: Record<string, any>
    export default hooks
    export const someProperty: number
}
默认导出包含多个属性
ts
// my-library.js
export default {
    myFunction(param) {
        return param.length
    },
    myConstant: 'Hello',
}

// types.d.ts
declare module 'my-library' {
    interface MyLibrary {
        myFunction(param: string): number
        myConstant: string
    }

    const lib: MyLibrary
    export default lib
}

// 使用
import myLibrary from 'my-library'

const result = myLibrary.myFunction('hello') // result 的类型是 number
console.log(myLibrary.myConstant) // myConstant 的类型是 string
复杂对象
ts
// my-library.js
export default {
    version: '1.0.0',
    utils: {
        add(a, b) {
            return a + b
        },
    },
}

// types.d.ts
declare module 'my-library' {
    interface Utils {
        add(a: number, b: number): number
    }

    interface MyLibrary {
        version: string
        utils: Utils
    }

    const lib: MyLibrary
    export default lib
}

// 使用
import myLibrary from 'my-library'

console.log(myLibrary.version) // version 的类型是 string
const result = myLibrary.utils.add(1, 2) // result 的类型是 number
默认导出 Class
ts
// my-library.js
export default class MyClass {
    constructor(value) {
        this.value = value
    }
    getValue() {
        return this.value
    }
}

// types.d.ts
declare module 'my-library' {
    class MyClass {
        constructor(value: string)
        getValue(): string
    }

    export default MyClass
}

// 使用
import MyClass from 'my-library'

const instance = new MyClass('hello')
const value = instance.getValue() // value 的类型是 string
默认导出函数 + 额外属性
ts
// my-library.js
function myFunction(param) {
    return param.length
}

myFunction.myConstant = 'Hello'

export default myFunction

// types.d.ts
declare module 'my-library' {
    interface MyFunction {
        (param: string): number
        myConstant: string
    }

    const myFunction: MyFunction
    export default myFunction
}

// 使用
import myFunction from 'my-library'

const result = myFunction('hello') // result 的类型是 number
console.log(myFunction.myConstant) // myConstant 的类型是 string

支持数组或对象解构

typescript
type ConvenientDeconstruction<T> = [any[], T] & { state: any[] } & T

declare function get<T>(): ConvenientDeconstruction<T>

const [state, { getState, setState }] = get<{ getState: () => any; setState: (v: any) => void }>()

// const { state, getState, setState } = get<{ getState: () => any, setState: (v: any) => void }>()