Skip to content

Conversation

@benzaria
Copy link
Contributor

@benzaria benzaria commented Sep 28, 2025

  • Fully supports optional elements (?) → returns boolean if the match is optional.
  • Full Supports for Arrays (Rest element)
  • Correctly handles required undefined separately from optional (?).
Feature Old New
Optional element support
Required undefined distinction
Rest element support
Result precision true/false true/false/boolean
Edge case coverage limited complete

@benzaria benzaria marked this pull request as draft September 28, 2025 18:26
@benzaria
Copy link
Contributor Author

After consideration a recursive types is better to cover the rest element cases.
if there is any trick that can be used in the first maped object type to handle the rest element, whoud that be better ?

@benzaria benzaria marked this pull request as ready for review September 29, 2025 20:44
Repository owner deleted a comment from claude bot Oct 6, 2025
@sindresorhus
Copy link
Owner

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);

@som-sm
Copy link
Collaborator

som-sm commented Oct 13, 2025

@sindresorhus

expectType<Includes<[true, false], boolean>>(false);

Umm, this should be true, because:

Includes<[true, false], boolean>
=> Includes<[true, false], true> | Includes<[true, false], false>
=> true | true
=> true

expectType<Includes<[boolean], boolean>>(true);

And, this should be boolean, because:

Includes<[boolean], boolean>
=> Includes<[true], true> | Includes<[true], false> | Includes<[false], true> | Includes<[false], false>
=> true | false | false | true
=> boolean

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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add:

expectType<Includes<[1, 3] | [2, 3], 5>>(false);

@sindresorhus
Copy link
Owner

@som-sm Includes here is exact-equality (IsEqual) based. No assignability, no distribution over Item. So I feel like this is correct:

  • Includes<[true, false], boolean> ⇒ false*
  • Includes<[boolean], boolean> ⇒ true
  • It only returns boolean when uncertainty is introduced by optionals/rest.

@som-sm
Copy link
Collaborator

som-sm commented Oct 13, 2025

@som-sm Includes here is exact-equality (IsEqual) based. No assignability, no distribution over Item. So I feel like this is correct:

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

@benzaria
Copy link
Contributor Author

I intentionally designed Includes to be strict following the original behavior.

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

@sindresorhus
Copy link
Owner

Yeah, I think a {distributeItem} option could be useful, but it should be off by default.

@benzaria benzaria requested a review from som-sm October 17, 2025 17:06
@sindresorhus sindresorhus changed the title remaster Includes type Improve Includes type Oct 18, 2025
@sindresorhus
Copy link
Owner

Missed this, it should be distributeItem singular, not plural. We are distributing the "Item" type.

@benzaria
Copy link
Contributor Author

Missed this, it should be distributeItem singular, not plural. We are distributing the "Item" type.

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.
Would you still prefer keeping it singular for consistency?

@sindresorhus
Copy link
Owner

I still prefer distributeItem (singular). While array elements do get distributed, that's an implementation detail of the comparison logic. The option specifically controls whether to distribute the Item parameter. The name should describe what the user is controlling (distribution of the Item type), not all the internal mechanics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants