如何实现验证元组每个项均已定义的Type Guard?
实现支持元组的非空数组类型守卫
原Stack Overflow上《Type guard for verifying that each item of an array is defined》的采纳方案无法处理元组场景,原方案代码如下:
function isDefined<T> (value: NonNullable<T> | undefined | null): value is NonNullable<T> { return value !== null && value !== undefined } function isEachItemDefined<T> (value: ReadonlyArray<NonNullable<T> | undefined | null>): value is ReadonlyArray<NonNullable<T>> { return value.every(isDefined) }
在如下元组场景中,该守卫无法正确推导元素类型:
type Test = { value: number }; const array: readonly [Test | null, Test | null] = [null, null]; if (isEachItemDefined(array)) { const [val1, val2] = array; // val1、val2仍为Test | null,不符合预期 }
要实现同时支持可变数组、只读数组、元组的非空类型守卫,需利用TypeScript的映射类型处理数组/元组的每个元素,而非统一转为ReadonlyArray。具体实现如下:
// 基础非空判断守卫 function isDefined<T>(value: T | null | undefined): value is NonNullable<T> { return value !== null && value !== undefined; } // 支持元组的数组非空守卫 function isEachItemDefined<T extends readonly (unknown | null | undefined)[]>( value: T ): value is { [K in keyof T]: NonNullable<T[K]> } { return value.every(isDefined); }
效果验证
元组场景
type Test = { value: number }; const array: readonly [Test | null, Test | null] = [{ value: 1 }, { value: 2 }]; if (isEachItemDefined(array)) { const [val1, val2] = array; // val1、val2类型均为Test,符合预期 }
普通数组场景
const normalArray: (Test | null)[] = [{ value: 3 }, { value: 4 }]; if (isEachItemDefined(normalArray)) { normalArray.forEach(item => { console.log(item.value); // item类型为Test,无类型报错 }); }
原理说明:通过泛型T extends readonly (unknown | null | undefined)[]约束输入为任意数组/元组,再用映射类型{ [K in keyof T]: NonNullable<T[K]> }移除每个元素的null和undefined类型,让TypeScript能正确推导元组每个位置的具体类型。
内容的提问来源于stack exchange,提问作者Paya
相关产品推荐
相关产品推荐

