Improve type guard for `.all`
It would be nice if this worked:
const a = foo();
const b = bar();
// Both `a` and `b` is an `object`, but TS only knows they're `any`.
if (is.all(is.object, a, b)) {
// `a` and `b` is now known by TS as `object`
}
There is a $30.00 open bounty on this issue. Add more on Issuehunt.
- Checkout the Issuehunt explorer to discover more funded issues.
- Need some help from other developers? Add your repositories on Issuehunt to raise funds.
That’s possible I guess if there’s a way to know if the predicate is a type guard predicate
We don’t need to know it’s a type guard. We can just pass on what TS infers, maybe by using the infer keyword: https://dev.to/miracleblue/how-2-typescript-serious-business-with-typescripts-infer-keyword-40i5
Someone mentions the "built in ReturnType<fn>" type, this might help...
altho, following this issue:
interface Array<T> {
filter<U extends T>(pred: (a: T) => a is U): U[];
}
type Predicate<T> = (value: unknown) => value is T;
is.all = <T>(predicate: Predicate<T>, ...values: unknown[]): values is T[] =>
predicateOnArray(Array.prototype.every, predicate, values);
does this look right?
Looks good. Can you do a PR? :)
@issuehunt has funded $30.00 to this issue.
- Submit pull request via IssueHunt to receive this reward.
- Want to contribute? Chip in to this issue via IssueHunt.
- Checkout the IssueHunt Issue Explorer to see more funded issues.
- Need help from developers? Add your repository on IssueHunt to raise funds.
I ran into this recently and tried the suggested fix, it looks like this isn't possible generically.
export type Predicate<T = unknown> = (value: unknown) => value is T;
is.all = <T>(predicate: Predicate<T>, ...values: unknown[]): values is T[] =>
predicateOnArray(Array.prototype.every, predicate, values);
Gives the error A type predicate cannot reference a rest parameter.ts (1229).
Apparently it also isn't possible to do this manually for a few arguments. This is a compile error (and all the other variants I tried).
function test(a: unknown, b: unknown): (a is true) & (b is true) {
return true;
}
@Gerrit0 Thanks for looking into it!
to what line does this error refer to? is it thrown from predicateOnArray or all?
Did you try to update predicateOnArray to have the second parameter be of type Predicate<T> as well?
The error is caused by values is T[] on all. Updating Predicate in the predicateOnArray function unfortunately has no effect since the type guard is lost (changed to just be boolean) when it is used in all (or any).
It is possible to achieve the goal in the OP with a different signature. This works as expected (no changes necessary for predicateOnArray).
is.allArray = <T>(predicate: Predicate<T>, values: unknown[]): values is T[] =>
predicateOnArray(Array.prototype.every, predicate, values)
Any update on this issue ?
@nicosayer I think you can use is.array(value, predicate) for that, does it help you?
@nicosayer I think you can use
is.array(value, predicate)for that, does it help you?
I am not sure how this helps, can you elaborate ?
To make sure everything is clear, this is how I would summarize the issue:
What is currently happening:
let a: string | number
let b: string | number
if (is.all(is.string, a, b)) {
// `a` and `b` are of type string | number
}
What is actually expected:
let a: string | number
let b: string | number
if (is.all(is.string, a, b)) {
// `a` and `b` are of type string
}
@nicosayer yeah my bad, I've been out of context for a while and thought it would work, but it doesn't type-guard the specific array items