如何在TypeScript中断言或推断getValidItems工具函数返回值为非空类型?
解决TypeScript对
getValidItems函数的类型推断问题 这个问题的核心在于,你的原getValidItems函数没有给TypeScript足够的类型信息来保证返回数组中的元素是非空的,而且泛型定义也没有明确转换后类型的非空约束。我们可以通过优化泛型、结合类型守卫和工具类型来修复这个问题。
问题分析
原函数的返回类型(TItem | TReturn)[]过于宽泛,TypeScript无法从运行时的if (outputItem)检查自动推断出类型层面的非空保证。此外,当你传递({ node }) => node作为转换函数时,node本身的类型是TNode | null | undefined,TypeScript没法知道这个转换后的结果会被过滤掉空值。
解决方案:优化getValidItems的类型定义与实现
我们可以利用TypeScript的NonNullable工具类型、类型守卫,以及更函数式的数组操作来让类型推断正常工作:
方案1:使用filter+类型守卫
这种写法更直观,filter的类型守卫会明确告诉TypeScript哪些元素是有效的:
export type Maybe<T> = T | null | undefined; export const getValidItems = <TItem, TReturn = TItem>( items: Maybe<TItem>[], transform?: (item: TItem) => TReturn ): NonNullable<TReturn>[] => { // 第一步:过滤掉原数组中的空值,类型守卫确保item是TItem const nonNullItems = items.filter((item): item is TItem => item != null); // 第二步:转换元素(如果有转换函数) const transformedItems = nonNullItems.map(item => transform?.(item) ?? item); // 第三步:过滤转换后的空值,类型守卫确保结果是非空的TReturn return transformedItems.filter((output): output is NonNullable<TReturn> => output != null); };
方案2:使用reduce构建结果数组
如果你更喜欢reduce的写法,也可以明确指定累加器的类型:
export type Maybe<T> = T | null | undefined; export const getValidItems = <TItem, TReturn = TItem>( items: Maybe<TItem>[], transform?: (item: TItem) => TReturn ): NonNullable<TReturn>[] => { return items.reduce<NonNullable<TReturn>[]>((validItems, item) => { if (item == null) return validItems; const outputItem = transform ? transform(item) : item; if (outputItem != null) { validItems.push(outputItem as NonNullable<TReturn>); } return validItems; }, []); };
方案3:使用flatMap简化逻辑
flatMap可以一次性完成过滤和转换,代码更简洁:
export type Maybe<T> = T | null | undefined; export const getValidItems = <TItem, TReturn = TItem>( items: Maybe<TItem>[], transform?: (item: TItem) => TReturn ): NonNullable<TReturn>[] => { return items.flatMap(item => { if (item == null) return []; const output = transform ? transform(item) : item; return output == null ? [] : [output as NonNullable<TReturn>]; }); };
验证效果
现在修改你的getNodes函数,TypeScript会正确推断返回类型为TNode[],且不会再提示“Object is possibly 'null' or 'undefined'”:
export const getNodes = <TNode>(data?: { edges?: { node?: TNode | null }[] | null }) => { const { edges } = data || {}; if (!edges) { return []; } // 现在nodes的类型被正确推断为TNode[] const nodes = getValidItems(edges, ({ node }) => node); return nodes; };
关键要点
NonNullable工具类型:明确告诉TypeScript返回的数组元素不包含null或undefined。- 类型守卫:在
filter中使用类型断言函数(如(item): item is TItem => ...),让TypeScript知道过滤后的元素类型。 - 泛型默认值:给
TReturn设置默认值TItem,确保不传递转换函数时,返回的是NonNullable<TItem>[]。
内容的提问来源于stack exchange,提问作者Zachary Danger Rabe
相关产品推荐
相关产品推荐

