ts 字符串模板类型 lodash get函数的类型推断和vuex 合法的 action

原创
09/13 16:46
阅读数 60

TypeScript 4.1 新特性:字符串模板类型,Vuex 终于有救了?

playground

 

联合类型在展开时会进行排列组合

type T0 = `${'top' | 'bottom'}-${'left' | 'right'}`;
// type T0 = "top-left" | "top-right" | "bottom-left" | "bottom-right"

 

有了四个关键字方便开发, 不知道后面会不会有驼峰转换的

大写, 小写, 首字母大写, 首字母小写

type T1<T extends string>  = `${uppercase T} ${lowercase T} ${capitalize T}  ${uncapitalize T} ` 

type T2 = T1<'heLLo'>
// type T2 = "HELLO hello HeLLo  heLLo "

type T3 = T1<'HeLLo'>
// type T3 = "HELLO hello HeLLo  heLLo "

 

配合infer实现类似正则表达式提取

type Pointer<S extends string> = S extends `[${infer X}-${infer Y}]` ? {x:X,y:Y} : unknown

type T4 = Pointer<'[1-2]'>
/**
 type T4 = {
    x: "1";
    y: "2";
}

 */

type T5 = Pointer<'[abc-efd]'>
/**
 type T5 = {
    x: "abc";
    y: "efd";
}
 */

 

配合拓展运算符和unfer递归实现列表的join

type List = (string | number | boolean | bigint)[]
type Join<T extends List, C extends string> = T extends [] ? '' :
    T extends [unknown] ? `${T[0]}` :
    T extends [unknown, ...infer U] ? `${T[0]}${C}${Join<U, C>}` : string

type T1 = Join<[1, 2, 3], '-'>
// type T1 = "1-2-3"

type T2 = Join<['a', 'b', 'c'], ','>
// type T2 = "a,b,c"

type T3 = Join<['a', 1, 3], '='>
// type T3 = "a=1=3"

 

匹配策略

两个infer不相邻的话是贪婪模式

type T4<S extends string> = S extends `${infer T}x` ?  T : unknown

type T5 = T4<'abcdx'>
// type T5 = "abcd"

type T6 = T4<'abcdxxxx'>
// type T6 = "abcdxxx"

两个infer相邻的话, 第一个只会匹配到第一个字符

type T1<S extends string> = S extends `${infer X}${infer Y}` ? [X,Y] : unknown

type T2 = T1<'abcd'>
// type T2 = ["a", "bcd"]

 

lodash get函数的类型, 支持任意路径的属性类型推断

type PropType<T, Path extends string> =
    string extends Path ? unknown :
    Path extends keyof T ? T[Path] :
    Path extends `${infer K}.${infer R}` ? K extends keyof T ? PropType<T[K], R> : unknown : unknown

declare function get<T, P extends string>(obj: T, path: P): PropType<T, P>

const stu = {
    name: 'ace',
    age: 18,
    class: {
        name: 'class name',
        teacher: {
            name: 'tea',
            id: 1234
        }
    }
}

const v0 = get(stu, 'age')
// const v0: number

const v1 = get(stu, 'class.aa')
// const v1: unknown

const v2 = get(stu, 'class.teacher.id')
// const v2: number

const v3 = get(stu, 'class.teacher')
/**
const v3: {
    name: string;
    id: number;
}
 */

 

为vuex的dispatch加类型, 不过一般好像都是直接 将字面量转成字符串常量使用的, 

type VuexOptions<M, N> = {
   namespace?: N,
   mutations: M,
}

type Action<M, N> = N extends string ? `${N}/${keyof M & string}` : keyof M

type Store<M, N> = {
   dispatch(action: Action<M, N>): void
}

declare function Vuex<M, N>(options: VuexOptions<M, N>): Store<M, N>

const store = Vuex({
   namespace: "cart" as const,
   mutations: {
      add() { },
      remove() { }
   }
})

store.dispatch("cart/add")
store.dispatch("cart/remove")
store.dispatch("cart/add2")

 

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部