考察如下类型: type PromiseType<T> = (args: any[]) => Promise<T>; 那么对于符合上面类型的一个方法,如何得知其 Promise 返回的类型? 譬如对于这么一个返回 async function stringPromise() {
return "string promise";
}
|
-
typescript cannot infer type
2020-12-07 01:28:32<p>Typescript cannot infer correctly the type, am I wrong somewhere? <p><img alt="Screenshot from 2019-03-30 13-00-47" src=... -
理解TypeScript中的infer关键字
2021-01-13 18:04:48 -
infer的用法_typescript高级用法之infer的理解与使用
2021-01-04 04:46:45Dooring特别版)在线IDE开发入门之从零实现一个在线代码编辑器基于React+Koa实现一个h5页面可视化编辑器-DooringTS核心知识点总结及项目实战案例分析前言以前一直不会用infer,要么直接就是returnType,压根不需要用...往期精彩
- 基于NodeJS从零构建线上自动化打包工作流(H5-Dooring特别版)
- 在线IDE开发入门之从零实现一个在线代码编辑器
- 基于React+Koa实现一个h5页面可视化编辑器-Dooring
TS核心知识点总结及项目实战案例分析
前言
以前一直不会用infer,要么直接就是returnType,压根不需要用infer,网上那些教程只给示例不给具体场景就无法让人很好理解这玩意。
类型分发
对于infer,最好应该先说一下类型分发,虽然他们关系不是太大,但是如果把infer与类型分发结合起来,让人一看就觉得这人ts水平可以。至于协变与逆变等概念会比较容易让人搞混乱,可以以后再掌握。
我以前也学过这个,但是并不是能完全掌握它的使用时机,也不知道如何用,所以看别人用能看懂和自己能用完全是2种状态。
首先看一下类型分发的基本例子:interface Fish { fish: string}interface Water { water: string}interface Bird { bird: string}interface Sky { sky: string}//naked typetype Condition = T extends Fish ? Water : Sky;let condition1: Condition = { water: '水' };let condition2: Condition = { sky: '天空' };
相信这个例子大家很容易理解,但是实际中什么时候用,怎么用,完全不知道。
这个例子有个特点,就是下面的condition1和condition2里定义的类型里所传的泛型与后面赋值的类型并不一样。
也就是说,类型分发一般是用来先知道已知类型,赋的值的类型会基于这个分发进行判断推出相应类型。
乍看之下好像还是没什么卵用,比如condition1,我都知道类型,我直接写个Sky|Water类型不香?干嘛二货的还搞个类型分发?
上面那个例子确实没啥卵用,但是如果判断继承的也是泛型,那么就可以快速取出一些类型,而不用自己重新去定义:(虽然这些很多都是内置的)
type Diff = T extends U ? never : T;type R = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d"type Filter = T extends U ? T : never;type R1 = Filter<string | number | boolean, number>;
既然有内置的,还不是没卵用。。。所以这就需要和infer联合使用才能看出牛b之处。
infer初探
infer大家应该都知道,returnType就是infer搞得,代码是这样:type ReturnTypeextends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any;
乍看之下好像有点难懂,其实仔细看发现还是很好理解的,它也是个类型分发。学到这里,很多人可能就只知道有这个东西,但是什么时候用Infer完全不知道,我也是这样,后来再次听课时突发灵感,发现这个infer其实就相当于占位,也就是一个不知道的类型,用infer X去给他占位,再结合类型分发,就能玩出花样来了。当时还有小伙伴这么问:ts不是能自动推断类型吗?为什么需要Infer X去推断类型。卧槽,这个问的太好了,这个就是理解Infer的关键。我们先结合个示例来进行说明:export {}type Parameters = T extends (...args: infer R) => any ? R : any;type T0 = Parameters<() => string>; // []type T1 = Parameters<(s: string) => void>; // [string]type T2 = Parameters<((arg: T) => T)>; // [unknown]
这个parameter也是内置的,可以看见,也是个类型分发,跟returnType区别就是infer X的占位跑到参数上去定义类型了。
如果我们把infer R换成已知类型,那么这个类型分发就跟一开始的demo没太大区别:
type Parameters = T extends (...args:string[]) => any ? string[] : any;type T0 = Parameters<() => string>;
如果不换成已知类型,那么只写R不写infer会报错,因为不知道R是什么东西。
那么如果通过泛型传呢?可惜args必须是个数组类型,所以用泛型传还得限定下它的条件:
type Parametersextends type T0 = Parameters<() => string,string[]>;
可以发现,这么传跟已知类型传其实没太大区别,因为在传第二个泛型的时候,这个类型我们是知道的,所以这种情况,也没什么太大用处,除非传泛型的是另一个人,那么我们在写这个库的时候,倒是可以拿到用户所定义的类型。这时倒是有点作用。
这样一换就可以发现,infer可以在类型推导中去占任何位置,最后的推导的类型可以借助这之间所需的类型。可以看下这个例子加深理解:
type T1 = { name: string }; type T2 = { age: number }; type UnionToIntersection = T extends { a: (x: infer U) => void; b: (x: infer U) => void } ? U : never; type T3 = UnionToIntersection(x: T1) =>
这个例子就是infer取得参数,两个函数的参数,对于为啥2个会出来交叉类型,这里是协变,所以是交叉类型。
下面看一下更难点的例子,来源于leetcode招聘:
https://github.com/LeetCode-OpenSource/hire/blob/master/typescript_zh.md
题目是这样:
interface Action { payload?: T; type: string; } class EffectModule { count = 1; message = "hello!"; delay(input: Promise<number>) { return input.then(i => ({ payload: `hello ${i}!`, type: 'delay' })); } setMessage(action: Action<Date>) { return { payload: action.payload!.getMilliseconds(), type: "set-message" }; } } // 修改 Connect 的类型,让 connected 的类型变成预期的类型 type Connect = (module: EffectModule) => any; const connect: Connect = m => ({ delay: (input: number) => ({ type: 'delay', payload: `hello 2` }), setMessage: (input: Date) => ({ type: "set-message", payload: input.getMilliseconds() }) }); type Connected = { delay(input: number): Action<string>; setMessage(action: Date): Action<number>; }; export const connected: Connected = connect(new EffectModule());
要求修改那个any,使其返回正确类型,而且这个类型要和connected一样。
有同学说,直接把any改成connected不就完了?要是这么简单也不会出这题。这个肯定是要你推出来,并且这个connected它的类型是EffectModule实例上的方法,里面的参数与返回还修改了。
这题怎么做呢,先一步步来,先提取出effectModule的方法,不然没法下一步。
提取class方法没有现成的,肯定不能keyof EffectModule,因为还有别的东西,怎么排除别的玩意呢?就是利用类型分发和class可以取值来做,如果是函数,那就提取,否则就不提取:
type MethodName = {[F in keyof T]:T[F] extends Function ? F:never}[keyof T] type EE = MethodName
这里同时利用value如果是never 则keyof就不会返回。这段其实挺有启发性,因为很多时候,都想搞个循环判断类型,然后进行选择,这就是个很好的范例。
拿到了name然后要改装方法它需要:
这个是题目给的,直接抄来:asyncMethod(input: Promise): Promise> asyncMethod(input: T): Action syncMethod(action: Action): Action syncMethod(action: T): Action
然后需要做一个类型分发,用来判断是哪个方法,再分发给哪个方法:type asyncMethod = (input: Promise) => Promise> type asyncMethodConnect = (input: T) => Action type syncMethod = (action: Action) => Action type syncMethodConnect = (action: T) => Action
这段很简单,就是分发判断,泛型是用infer占位ok。最后,修改connect,就大功告成.type EffectMethodAssign = T extends asyncMethod
? asyncMethodConnect
: T extends syncMethod
? syncMethodConnect
: never
type Connect = (module: EffectModule) => { [F in MethodName<typeof module>]:EffectMethodAssign<typeof module[F]> }
-
TypeScript `infer` 关键字
2019-05-28 23:39:00考察如下类型: type PromiseType ...如果你对 TypeScript 不是那么陌生,可能知道官方类型库中提供了 ...infer ...infer ...infer ...转载于:https://www.cnblogs.com/Wayou/p/typescript_infer.html转载于:https://www.cnblogs.com/Wayou/p/typescript_infer.html
-
[TypeScript] Props type infer
2021-01-07 11:52:20<div><p>I met a problems here. And here is my solution. I wonder if there is any other solution which is better? <pre><code> props:{ src: { type: String, required: true } }, setup(props){ ... -
【typescript】infer的理解与使用
2020-08-28 07:45:43前言 以前一直不会用infer,要么直接就是returnType,压根不需要用infer,网上那些教程只给示例不给具体场景就无法让人很好理解这玩意,并且很好前言
- 以前一直不会用infer,要么直接就是returnType,压根不需要用infer,网上那些教程只给示例不给具体场景就无法让人很好理解这玩意。
类型分发
- 对于infer,最好应该先说一下类型分发,虽然这2关系不是太大,但是如果把infer与类型分发结合起来,让人一看就觉得这人ts水平可以。至于协变与逆变等概念会比较容易让人搞混乱,可以以后再掌握。
- 我以前也学过这个,但是并不是能完全掌握它的使用时机,也不知道如何用,所以看别人用能看懂和自己能用完全是2种状态。
- 首先看一下类型分发的基本例子:
interface Fish { fish: string } interface Water { water: string } interface Bird { bird: string } interface Sky { sky: string } //naked type type Condition<T> = T extends Fish ? Water : Sky; let condition1: Condition<Fish | Bird> = { water: '水' }; let condition2: Condition<Fish | Bird> = { sky: '天空' };
- 相信这个例子大家很容易理解,但是实际中什么时候用,怎么用,完全不知道。
- 这个例子有个特点,就是下面的condition1和condition2里定义的类型里所传的泛型与后面赋值的类型并不一样。
- 也就是说,类型分发一般是用来先知道已知类型,赋的值的类型会基于这个分发进行判断推出相应类型。
- 乍看之下好像还是没什么卵用,比如condition1,我都知道类型,我直接写个Sky|Water类型不香?干嘛二货的还搞个类型分发?
- 上面那个例子确实没啥卵用,但是如果判断继承的也是泛型,那么就可以快速取出一些类型,而不用自己重新去定义:(虽然这些很多都是内置的)
type Diff<T, U> = T extends U ? never : T; type R = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d" type Filter<T, U> = T extends U ? T : never; type R1 = Filter<string | number | boolean, number>;
- 既然有内置的,还不是没卵用。。。所以这就需要和infer联合使用才能看出牛b之处。
infer
- infer大家应该都知道,returnType就是infer搞得,代码是这样:
type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any;
- 乍看之下好像有点难懂,其实仔细看发现还是很好理解的,它也是个类型分发。
- 学到这里,很多人可能就只知道有这个东西,但是什么时候用Infer完全不知道,我也是这样,后来再次听课时突发灵感,发现这个infer其实就相当于占位,也就是一个不知道的类型,用infer X去给他占位,再结合类型分发,就能玩出花样来了。当时还有小伙伴这么问:ts不是能自动推断类型吗?为什么需要Infer X去推断类型。卧槽,这个问的太好了,这个就是理解Infer的关键。
- 我们先结合个示例来进行说明:
export {} type Parameters<T> = T extends (...args: infer R) => any ? R : any; type T0 = Parameters<() => string>; // [] type T1 = Parameters<(s: string) => void>; // [string] type T2 = Parameters<(<T>(arg: T) => T)>; // [unknown]
- 这个parameter也是内置的,可以看见,也是个类型分发,跟returnType区别就是infer X的占位跑到参数上去定义类型了。
- 如果我们把infer R换成已知类型,那么这个类型分发就跟一开始的demo没太大区别:
type Parameters<T> = T extends (...args:string[]) => any ? string[] : any; type T0 = Parameters<() => string>;
- 如果不换成已知类型,那么只写R不写infer会报错,因为不知道R是什么东西。
- 那么如果通过泛型传呢?可惜args必须是个数组类型,所以用泛型传还得限定下它的条件:
type Parameters<T,R extends Array<any>> = T extends (...args:R) => any ? R : any; type T0 = Parameters<() => string,string[]>;
- 可以发现,这么传跟已知类型传其实没太大区别,因为在传第二个泛型的时候,这个类型我们是知道的,所以这种情况,也没什么太大用处,除非传泛型的是另一个人,那么我们在写这个库的时候,倒是可以拿到用户所定义的类型。这时倒是有点作用。
- 这样一换就可以发现,infer可以在类型推导中去占任何位置,最后的推导的类型可以借助这之间所需的类型。可以看下这个例子加深理解:
type T1 = { name: string }; type T2 = { age: number }; type UnionToIntersection<T> = T extends { a: (x: infer U) => void; b: (x: infer U) => void } ? U : never; type T3 = UnionToIntersection<{ a: (x: T1) => void; b: (x: T2) => void }>; // T1 & T2
- 这个例子就是infer取得参数,两个函数的参数,对于为啥2个会出来交叉类型,这里是协变,所以是交叉类型。
- 下面看一下更难点的例子,来源于leetcode招聘:
- https://github.com/LeetCode-OpenSource/hire/blob/master/typescript_zh.md
- 题目是这样:
interface Action<T> { payload?: T; type: string; } class EffectModule { count = 1; message = "hello!"; delay(input: Promise<number>) { return input.then(i => ({ payload: `hello ${i}!`, type: 'delay' })); } setMessage(action: Action<Date>) { return { payload: action.payload!.getMilliseconds(), type: "set-message" }; } } // 修改 Connect 的类型,让 connected 的类型变成预期的类型 type Connect = (module: EffectModule) => any; const connect: Connect = m => ({ delay: (input: number) => ({ type: 'delay', payload: `hello 2` }), setMessage: (input: Date) => ({ type: "set-message", payload: input.getMilliseconds() }) }); type Connected = { delay(input: number): Action<string>; setMessage(action: Date): Action<number>; }; export const connected: Connected = connect(new EffectModule());
- 要求修改那个any,使其返回正确类型,而且这个类型要和connected一样。
- 有同学说,直接把any改成connected不就完了?要是这么简单也不会出这题。这个肯定是要你推出来,并且这个connected它的类型是EffectModule实例上的方法,里面的参数与返回还修改了。
- 这题怎么做呢,先一步步来,先提取出effectModule的方法,不然没法下一步。
- 提取class方法没有现成的,肯定不能keyof EffectModule,因为还有别的东西,怎么排除别的玩意呢?就是利用类型分发和class可以取值来做,如果是函数,那就提取,否则就不提取:
type MethodName<T> = {[F in keyof T]:T[F] extends Function ? F:never}[keyof T] type EE = MethodName<EffectModule>
- 这里同时利用value如果是never 则keyof就不会返回。这段其实挺有启发性,因为很多时候,都想搞个循环判断类型,然后进行选择,这就是个很好的范例。
- 拿到了name然后要改装方法它需要:
asyncMethod<T, U>(input: Promise<T>): Promise<Action<U>> 变成了 asyncMethod<T, U>(input: T): Action<U> syncMethod<T, U>(action: Action<T>): Action<U> 变成了 syncMethod<T, U>(action: T): Action<U>
- 这个是题目给的,直接抄来:
type asyncMethod<T, U> = (input: Promise<T>) => Promise<Action<U>> type asyncMethodConnect<T, U> = (input: T) => Action<U> type syncMethod<T, U> = (action: Action<T>) => Action<U> type syncMethodConnect<T, U> = (action: T) => Action<U>
- 然后需要做一个类型分发,用来判断是哪个方法,再分发给哪个方法:
type EffectMethodAssign<T> = T extends asyncMethod<infer U, infer V>? asyncMethodConnect<U, V> : T extends syncMethod<infer U, infer V> ? syncMethodConnect<U, V> : never
- 这段很简单,就是分发判断,泛型是用infer占位ok。
- 最后,修改connect,就大功告成
type Connect = (module: EffectModule) => { [F in MethodName<typeof module>]:EffectMethodAssign<typeof module[F]> };
-
Typescript: Reactive assignments do not infer data type
2020-12-29 12:58:13Seems to be safe enough to infer the data type as boolean. <p><strong>System (please complete the following information): OS: Mac OS 10.15.3 IDE: VS Code Plugin/Package: Svelte for VS Code (the new ... -
巧用 TypeScript(五)-- infer
2019-03-14 13:51:31infer 最早出现在此 PR 中,表示在 extends 条件语句中待推断的类型变量。 简单示例如下: type ParamType<T> = T extends (param: infer P) => any ? P : T; 复制代码在这个条件语句 T extends (param: ... -
TypeScript extends,infer,keyof , 内置类型ReturnType,Partial,Readonly等
2020-06-27 15:42:32在 2.8 版本中,TypeScript 内置了一些与infer 有关的映射类型: 官网 Utility Types 文章目录infer用在函数中构造函数中内置类型ReturnType infer infer 最早出现在此 PR 中,表示在 extends 条件语句中待推断的... -
typescript高级用法之infer的理解与使用
2020-09-29 17:51:14下面看一下更难点的例子,来源于leetcode招聘: https://github.com/LeetCode-OpenSource/hire/blob/master/typescript_zh.md 题目是这样: interface Action { payload?: T; type: string; } class EffectModule {... -
Typescript doesn't infer type of component imported from .vue
2021-01-11 01:03:10<div><p>On this import statement: <pre><code> import myComponent from ./myComponent.vue </code></pre> <p>myComponent has the type of Vue....go to defintion"...microsoft/TypeScript-Vue-Starter</p></div> -
TypeScript 4.1 and template literal types to infer Request Params
2021-01-10 18:10:36We could try to infer the request params from the URL by using template literal types (introduced in TS 4.1). See this ;4.1.0-pr-40336-88#code/C4TwDgpgBAogHsATgQwMbAEoHsCuwIAKyKAtgM4A8... -
[TypeScript] Infer the Return Type of a Generic Function Type Parameter
2019-01-24 20:15:00When working with conditionals types, within the “extends” expression, we can use the “infer” keyword to either get the type of the elements of an array, or even to get the return type of a ... -
Add TypeScript definitions to enforce or infer whether properties are required.
2021-01-11 21:08:34<div><p>Alternative to PR #112 (documented in #109). <strong>Introduces breaking changes</strong></p> <ul><li>Introduce <code>FSAWithPayload</code> and <code>ErrorFSAWithPayload</code></li><li>...