回调函数 Promise 化 举个例子:
1 2 3 4 5 6 const promisifyTimeOut = (timeout ) => new Promise ((resolve ) => { setTimeout (() => { resolve (); }, time); });
再例如 UniAPP 封装微信小程序的大部分 API,既可以通过 callback 进行回调,也可以使用 Promise 回调:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 uni.login ({ success (res ) { if (res.code ) { } else { console .log ("登录失败!" + res.errMsg ); } }, }); uni.login ().then ((res ) => { if (res.code ) { } else { console .log ("登录失败!" + res.errMsg ); } });
如何在声明时通过判断传入的参数中是否有 success 回调判断返回值的类型?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 interface Res { [key : string ]: any ; }interface Options { [key : string ]: any ; success?: (result : Res ) => void ; fail?: (result : any ) => void ; complete?: (result : any ) => void ; }type PromisifySuccessResult < P, T extends { success?: (...args : any [] ) => void ; }, R = void > = P extends { success : any ; } ? R : P extends { fail : any } ? R : P extends { complete : any } ? R : Promise <Parameters <Exclude <T["success" ], undefined >>[0 ]>;type ProFunc = <T extends Options = Options >( options?: T ) => PromisifySuccessResult <T, Options >;
(2023.06.01 更新)一种特殊情况,关于泛型约束的默认值 例子:
1 2 3 4 5 6 7 8 9 function handleDateFormat (date?: Date ) { if (!date) { return ; } return date.getTime (); }const str = handleDateFormat (new Date ()); const str2 = handleDateFormat ();
从函数实现逻辑来看,当传入参数时函数一定会返回一个 number 类型,只有当不传参数才会返回 undefined,但 ts 似乎并不能识别出来,这种情况下就需要使用函数重载去手动声明。
优化后:
1 2 3 4 5 6 7 8 9 10 11 12 function handleDateFormat<T extends Date | undefined >( date?: T ): T extends Date ? number : undefined ;function handleDateFormat (date?: Date ) { if (!date) { return ; } return date.getTime (); }const str = handleDateFormat (new Date ()); const str2 = handleDateFormat ();
通过泛型约束,发现 str 已经能正确识别出返回值为 number 类型,但 str2 还是无法识别。
原因是声明中将 date 设置成了一个可选的参数,当 date 不传时 T 并没有获得类型,所以也没办法对返回值进行约束,如果调用改成:
1 const str2 = handleDateFormat (undefined );
只有传入参数,哪怕是 undefined, str2 才能获得正确的类型。
那么如果让不传参数的使用也能正确返回 undefined 类型呢?我们只需要给泛型 T 一个默认值就可以:
1 2 3 4 5 6 7 8 9 10 11 12 function handleDateFormat<T extends Date | undefined = undefined >( date?: T ): T extends Date ? number : undefined ;function handleDateFormat (date?: Date ) { if (!date) { return ; } return date.getTime (); }const str = handleDateFormat (new Date ()); const str2 = handleDateFormat ();
巧妙的点在于泛型约束的参数也能设置默认值,这样即使 date 参数没有传入,ts 依然能正确识别 T 的类型,从而判断正确的返回值类型。
涉及到的 TS 高级类型 条件类型约束
1 type MessageOf <T extends { message : unknown }> = T["message" ];
infer infer 语法的限制如下:
infer 只能在条件类型的 extends 子句中使用 infer 得到的类型只能在 true 语句中使用, 即 X 中使用
1 2 3 4 5 type InferArray <T> = T extends (infer U)[] ? U : never ; type InferFirst <T extends unknown []> = T extends [infer P, ...infer _] ? P : never ; type InferPromise <T> = T extends Promise <infer U> ? U : never ;
Parameters 1 2 3 4 5 type Parameters <T extends (...args : any ) => any > = T extends ( ...args : infer P ) => any ? P : never ;
提取 Type 中所有能够赋值给 Union 的属性,将这些属性构成一个新的类型
1 2 type Extract <T, U> = T extends U ? T : never ;type T0 = Extract <"a" | "b" | "c" , "a" | "f" >;
Exclude<UnionType, ExcludedMembers>
从 UnionType 中去掉所有能够赋值给 ExcludedMembers 的属性,然后剩下的属性构成一个新的类型
1 2 type Exclude <T, U> = T extends U ? never : T;type T0 = Exclude <"a" | "b" | "c" , "a" >;
Pick<Type, Keys>
从 Type 中选取一系列的属性,这些属性来自于 Keys(字符串字面量或字符串字面量的联合类型),用这些属性构成新的 type。
1 2 3 4 5 6 7 8 9 10 11 12 13 type Test = { name : string ; age : number ; salary?: number ; };type picked = Pick <Test , "name" | "age" >;
Omit<Type, Keys>
从 Type 中选取所有的属性值,然后移除属性名在 Keys 中的属性值
本质上是 Pick 的反向操作,排除掉 Keys。 Omit 相对而言复杂一些
1 2 3 4 5 6 7 8 9 10 11 type Test = { name : string ; age : number ; salary?: number ; };type omitted = Omit <Test , "age" >;
但 omit 和 pick 在特殊情况下有一点区别:
1 2 type picked = Pick <"a" | "b" , "a" >; type omitted = Omit <"a" | "b" , "a" >;
omit 源码:
1 type Omit <T, K extends keyof any > = Pick <T, Exclude <keyof T, K>>;
T 如果是个对象,那么 typeof T 就是对象上的属性,那么 K 就和对象上的属性对比就可以,但如果 T 是个 string 类型,那么 keyof T 会获得字符串类型上的所有方法,K 自然不会匹配到这些方法,然后这个类型就变成了:
1 type omitted = Omit <"a" | "b" , "a" > = Pick <"a" | "b" , keyof "a" | "b" > = keyof "a" | "b"