typescript 中的 infer 关键字的理解
infer 这个关键字,整理记录一下,避免后面忘记了。有点难以理解呢。
infer
infer 是在 typescript 2.8中新增的关键字。
infer 可以在 extends 条件类型的字句中,在真实分支中引用此推断类型变量,推断待推断的类型。
例如:用infer推断函数的返回值类型
type ReturnType = T extends (...args: any[]) => infer R ? R : any;
type fn = () => number
type fnReturnType = ReturnType // number
在这个例子中,
T extends U ? X : Y的形式为条件类型。
infer R代表待推断的返回值类型,如果T是一个函数(...args: any[]) => infer R,则返回函数的返回值R,否则返回any
案例:加深理解
反解 Promise
// promise 响应类型
type PromiseResType = T extends Promise ? R : T
// 验证
async function strPromise() {
return 'string promise'
}
interface Person {
name: string;
age: number;
}
async function personPromise() {
return {
name: 'p',
age: 12
} as Person
}
type StrPromise = ReturnType // Promise
// 反解
type StrPromiseRes = PromiseResType // str
type PersonPromise = ReturnType // Promise
// 反解
type PersonPromiseRes = PromiseResType // Person
反解函数入参类型
type Fn = (...args: A) => any
type FnArgs = T extends Fn ? A : any
function strFn (name: string) {
}
type StrFn = FnArgs // [string]
tuple 转 union ,如:[string, number] -> string | number
type ElementOf = T extends Array ? E : never
type TTuple = [string, number];
type ToUnion = ElementOf; // string | number
new 操作符
// 获取参数类型
type ConstructorParameters any> = T extends new (...args: infer P) => any ? P : never;
// 获取实例类型
type InstanceType any> = T extends new (...args: any[]) => infer R ? R : any;
class TestClass {
constructor(
public name: string,
public string: number
) {}
}
type Params = ConstructorParameters; // [string, numbder]
type Instance = InstanceType; // TestClass
react - reducer
// 定义
function useReducer, I>(
reducer: R,
// ReducerState 推断类型
initializerArg: I & ReducerState,
initializer: (arg: I & ReducerState) => ReducerState
): [ReducerState, Dispatch>];
// infer推断
type ReducerState> = R extends Reducer
? S
: never;
// Reducer类型
type Reducer = (prevState: S, action: A) => S;
// 使用 reducer
const reducer = (x: number) => x + 1;
const [state, dispatch] = useReducer(reducer, '');
// Argument of type "" is not assignable to parameter of type 'number'.
vue3 - ref
export interface Ref {
[isRefSymbol]: true
value: T
}
export function ref(value: T): T extends Ref ? T : Ref>
export type UnwrapRef = {
cRef: T extends ComputedRef ? UnwrapRef : T
ref: T extends Ref ? UnwrapRef : T
array: T
object: { [K in keyof T]: UnwrapRef }
}[T extends ComputedRef
? 'cRef'
: T extends Array
? 'array'
: T extends Ref | Function | CollectionTypes | BaseTypes
? 'ref' // bail out on types that shouldn't be unwrapped
: T extends object ? 'object' : 'ref']
// 使用
const count = ref({
foo: ref('1'),
bar: ref(2)
})
// 推断出
const count: Ref<{
foo: string;
bar: number;
}>
const count = ref(2) // Ref
const count = ref(ref(2)) // Ref
参考
- 理解TypeScript中的infer关键字
- Vue3 跟着尤雨溪学 TypeScript 之 Ref 类型从零实现
- 巧用 TypeScript(五)---- infer