Improve Includes type#1252
Conversation
|
After consideration a recursive types is better to cover the rest element cases. |
|
Suggestions for some more tests: expectType<Includes<readonly [1, 2?, 3?], 2>>(boolean);
expectType<Includes<[1?, 2?, 3?], 1>>(boolean);
expectType<Includes<[1?, 2?, 3?], 4>>(false);
expectType<Includes<[unknown], unknown>>(true);
expectType<Includes<[unknown], string>>(false);
expectType<Includes<[1, unknown], unknown>>(true);
expectType<Includes<[null], null>>(true);
expectType<Includes<[null], undefined>>(false);
expectType<Includes<[true, false], true>>(true);
expectType<Includes<[true, false], boolean>>(false);
expectType<Includes<[boolean], boolean>>(true); |
Umm, this should be
And, this should be |
| expectType<Includes<[1 | 2, 3], 1>>(false); | ||
| expectType<Includes<[1 | 2, 3], 1 | 2>>(true); | ||
| expectType<Includes<[1, 3] | [2, 3], 3>>(true); | ||
| expectType<Includes<[1, 3] | [2, 3], 1>>(boolean); |
There was a problem hiding this comment.
Add:
expectType<Includes<[1, 3] | [2, 3], 5>>(false);|
@som-sm
|
@sindresorhus Umm...ok gotcha, but in my experience distributing is usually a good idea. I'm not sure of good use cases for this type, but here's a quick, contrived example: declare function includes<
const T extends readonly unknown[],
const Target extends Includes<T, Target> extends false ? never : unknown,
>(array: T, target: Target): void;
includes([1, 2, 3] as [1, 2, 3 | 4], 4); // Errors, but shouldn't
// Argument of type '4' is not assignable to parameter of type 'never'@benzaria Could you share some practical, real-world examples for this type? |
|
I intentionally designed But @som-sm had a good point of adding distribution, which can be useful. I can add an option, that triggers it and make it false by default. @sindresorhus WDYT |
|
Yeah, I think a |
|
Missed this, it should be |
I did notice that, but in this case, we’re actually distributing both the Item type and the array element types — that’s why I chose the plural form. |
|
I still prefer |
|
Some more things:
Because the comparison path uses a strict-extends helper that returns
That feels too strong for uncertainty semantics. I’d expect
The previous tests checked invalid generic usage (missing generics, non-array input, etc.). Those checks are now gone, so regressions in input constraints could slip through.
Opn question: is the |
| expectType<Includes<[unknown], string>>(false); | ||
| expectType<Includes<[1, unknown], unknown>>(true); | ||
| expectType<Includes<any, any>>({} as any); | ||
| expectType<Includes<never, never>>({} as never); |
There was a problem hiding this comment.
| expectType<Includes<never, never>>({} as never); | |
| expectType<Includes<never, never>>({} as never); | |
| // ---------- Invalid usage ---------- | |
| // @ts-expect-error | |
| type IncludesMissingGenerics = Includes; | |
| // @ts-expect-error | |
| type IncludesMissingItem = Includes<[1, 2, 3]>; | |
| // @ts-expect-error | |
| type IncludesWithNonArrayInput = Includes<'abc', 'a'>; | |
| // @ts-expect-error | |
| type IncludesWithObjectInput = Includes<{key: 'value'}, 7>; | |
| // @ts-expect-error | |
| type IncludesWithInvalidOptions = Includes<[1], 1, {distributeItem: 1}>; |
booleanif the match is optional.true/falsetrue/false/boolean