// 安全处理返回值 asyncfunctionhandleData() { const data = awaitfetchData("/api/user");
// 第一步:判断是否是对象(排除 null) if (typeof data === "object" && data !== null) { // 第二步:判断是否包含 name 属性 if ("name"in data && typeof (data as { name: unknown }).name === "string") { // 安全访问 name 属性 console.log("用户名:", (data as { name: string }).name); }
// 第三步:判断是否包含 age 属性 if ("age"in data && typeof (data as { age: unknown }).age === "number") { console.log("年龄:", (data as { age: number }).age); } } }
映射类型
基本语法:{ [K in Keys]: T } 其实就类似 js 中的 for in语句,用于遍历 Keys 中的所有类型
比较常见的语法
1 2 3 4 5 6
{ [ P in K ] : T } { [ P in K ] ?: T } { [ P in K ] -?: T } { readonly [ P in K ] : T } { readonly [ P in K ] ?: T } { -readonly [ P in K ] ?: T }
利用映射类型实现的utility type
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
typeGetters<T> = { [K in keyof T as`get${Capitalize<string & K>}`]: () => T[K] };
// ❌ K 是 "color"(不属于 keyof product) getProperty(product, "color"); // 报错:Argument of type '"color"' is not assignable to parameter of type '"name" | "price" | "stock"'
infer关键字
infer = 类型层面的 “变量”,仅能在 T extends U ? X : Y 这种条件类型中使用 作用是「捕获 / 提取」复杂类型的某一部分(比如函数返回值、数组元素类型),并给这部分类型起一个变量名供后续使用
提取数组元素类型
1 2
typeArrayItem<T> = T extends (infer U)[] ? U : never; // 这里T extends (infer U)[] ? U : never;的意思是,如果T是某个待推断类型的数组,则返回推断的类型,否则返回never
提取函数返回值类型
1 2 3 4 5
typeGetReturn<T> = T extends (...args: any[]) => infer R ? R : never;
constreducer = (x: number) => x + 1; const [state, dispatch] = useReducer(reducer, ''); // Argument of type "" is not assignable to parameter of type 'number'.
这里useReducer会报一个类型错误,说””不能赋值给number类型
那React这里是如何通过reducer函数的类型来判断state的类型的?
直接看源码:
1 2 3 4 5 6 7 8 9 10 11 12 13
function useReducer<R extendsReducer<any, any>, I>( reducer: R, // ReducerState 推断类型 initializerArg: I & ReducerState<R>, initializer: (arg: I & ReducerState<R>) =>ReducerState<R> ): [ReducerState<R>, Dispatch<ReducerAction<R>>];
// infer推断 typeReducerState<R extendsReducer<any, any>> = R extendsReducer<infer S, any> ? S : never; // Reducer类型 typeReducer<S, A> = (prevState: S, action: A) => S;