I know for a single variable I can create a typeguard function to determine its type narrowing as follows:
function assert<T>(value: T | null | undefined): value is T {
return value != null;
}
const value: string | null = unknown();
if (assert(value)) {
// value must be a string
}
But is there a way to do this for an array of unknown length, ideally of potentially different types, i.e.
function assertValues<T>(...values: Array<T | null | undefined>): values is T[] {
return values.filter(value => value == null).length === 0;
}
const value1: string | null = unknown1();
const value2: number | null = unknown2();
if (assertValues(value1, value2)) {
// value1 must be a string
// value2 must be a number
}
The second example gives a syntax error: A type predicate cannot reference a rest parameter
, but is there an alternative way of achieving this in just one function?
I know for a single variable I can create a typeguard function to determine its type narrowing as follows:
function assert<T>(value: T | null | undefined): value is T {
return value != null;
}
const value: string | null = unknown();
if (assert(value)) {
// value must be a string
}
But is there a way to do this for an array of unknown length, ideally of potentially different types, i.e.
function assertValues<T>(...values: Array<T | null | undefined>): values is T[] {
return values.filter(value => value == null).length === 0;
}
const value1: string | null = unknown1();
const value2: number | null = unknown2();
if (assertValues(value1, value2)) {
// value1 must be a string
// value2 must be a number
}
The second example gives a syntax error: A type predicate cannot reference a rest parameter
, but is there an alternative way of achieving this in just one function?
- 2 "The second example gives a syntax error", could you include that in the question? Are you referring to "A type predicate cannot reference a rest parameter."? – DBS Commented Mar 10 at 14:48
- You can type guard an array, but not a rest parameter, so the best you can get here is something like this playground link, which is necessarily redundant (you need to pack the elements into an array, then unpack them from the same array). Does that fully address the question? If so I'll write a full answer explaining. If not, what am I missing? – jcalz Commented Mar 10 at 14:55
1 Answer
Reset to default 0Given the restriction you could actually return false or the asserted structure like an array or an object. An interesting solution could be using a callback with verified elements.
Playground
function assertValues<const T extends any[]>(...values: T){
return values.some(value => value == null) ? false as const : values as {[I in keyof T]: T[I] & {}};
}
function assertValues2<T extends object>(values: T){
return Object.values(values).some(value => value == null) ? false as const : values as {[K in keyof T]: T[K] & {}};
}
function assertValues3<const T extends any[]>(...args: [...T, (...arr: {[I in keyof T]: T[I] & {}}) => any]): boolean {
const values = args.slice(0, -1);
const fn = args.at(-1);
if(values.some(value => value == null)) return false;
if(typeof fn === 'function'){
(fn as any)(...values);
}
return true;
}
declare const value1: string | null;
declare const value2: number | null;
let arr = assertValues(value1, value2);
if (arr) {
const [value1, value2] = arr;
}
let obj = assertValues2({value1, value2});
if (obj) {
obj.value1;
obj.value2;
}
assertValues3(value1, value2, (value1, value2) =>{
value1;
value2;
});
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744841309a4596571.html
评论列表(0条)