sindresorhus/is

Do you want to work on this issue?

You can request for a bounty in order to promote it!

Improve type guard for `.all` #81

sindresorhus posted onGitHub

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`
}

That’s possible I guess if there’s a way to know if the predicate is a type guard predicate

posted by gioragutt about 6 years ago

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

posted by sindresorhus about 6 years ago

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?

posted by gioragutt about 6 years ago

Looks good. Can you do a PR? :)

posted by sindresorhus about 6 years ago

@issuehunt has funded $30.00 to this issue.


posted by IssueHuntBot almost 6 years ago

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;
}
posted by Gerrit0 almost 6 years ago

@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?

posted by gioragutt almost 6 years ago

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)
posted by Gerrit0 almost 6 years ago

Any update on this issue ?

posted by nicosayer about 3 years ago

@nicosayer I think you can use is.array(value, predicate) for that, does it help you?

posted by gioragutt about 3 years ago

@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
}
posted by nicosayer about 3 years ago

@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

posted by gioragutt about 3 years ago

Fund this Issue

$30.00
Funded
Only logged in users can fund an issue

Pull requests

Recent activities

issuehunt funded 30.00 for sindresorhus/is# 81
almost 6 years ago