Skip to content

Add AllExtend type#1164

Merged
sindresorhus merged 7 commits intomainfrom
feat/add-every-type
Jun 5, 2025
Merged

Add AllExtend type#1164
sindresorhus merged 7 commits intomainfrom
feat/add-every-type

Conversation

@som-sm
Copy link
Collaborator

@som-sm som-sm commented Jun 4, 2025

This PR fixes all the known limitations of the internal Every type and makes it publicly available.

- This type is not designed to be used with non-tuple arrays (like `number[]`), tuples with optional elements (like `[1?, 2?, 3?]`), or tuples that contain a rest element (like `[1, 2, ...number[]]`).


Introduced a new CollapseRestElement type to handle arrays with rest and optional elements. This utility replaces the rest element with a single element that has the same type as the rest element. For example, CollapseRestElement<[string, ...number[], boolean]> returns [string, number, boolean].

Before Every performs its computation, the input array is simplified using CollapseRestElement. This simplification shouldn't alter the result of Every because the expected output for [number, …string[], boolean] and [number, string, boolean] is the same.

@som-sm som-sm requested review from Copilot and sindresorhus June 4, 2025 15:31

This comment was marked as outdated.

@sindresorhus
Copy link
Owner

Should it maybe be called AllExtend? I feel that is clearer than Every because it explicitly conveys the type-level intent: checking whether all elements extend a given type. Every is vague and sounds like an operation or transformation rather than a boolean predicate.

/*
Indicates the value of `exactOptionalPropertyTypes` compiler option.
*/
type ExactOptionalPropertyTypesEnabled = [(string | undefined)?] extends [string?]
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
type ExactOptionalPropertyTypesEnabled = [(string | undefined)?] extends [string?]
export type ExactOptionalPropertyTypesEnabled = [(string | undefined)?] extends [string?]

I wonder why TS doesn't warn about this, even with ESM...

Copy link
Owner

Choose a reason for hiding this comment

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

And maybe prefix with Is

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I wonder why TS doesn't warn about this, even with ESM...

Umm... not sure why, maybe it's treating the module as "ambient".

test-d/every.ts Outdated
expectType<NonStrictNeverEvery<[never, any, never, any], never>>({} as boolean);

expectType<Every<any, never>>(false);
expectType<Every<never, any>>(false);
Copy link
Owner

Choose a reason for hiding this comment

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

Maybe also:

expectType<Every<unknown[], number>>({} as boolean);
expectType<Every<unknown[], any>>(true);

expectType<Every<[never, 1], any>>(true);
expectType<Every<[1, never], any>>(true);
expectType<Every<[never, ...never[], never], any>>(true);

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@sindresorhus Shouldn't Every<unknown[], number> return false and not boolean, because unknown extends number is not true.

type T = unknown extends number ? 'Y' : 'N';
//=> 'Y'

Every<any[], number> returns boolean because any distributes over conditionals.

type T = any extends number ? 'Y' : 'N';
//=> 'Y' | 'N'

Copy link
Owner

Choose a reason for hiding this comment

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

You're right 👍

@som-sm
Copy link
Collaborator Author

som-sm commented Jun 5, 2025

Should it maybe be called AllExtend? I feel that is clearer than Every because it explicitly conveys the type-level intent: checking whether all elements extend a given type. Every is vague and sounds like an operation or transformation rather than a boolean predicate.

I chose the name Every to match the naming with Array.prototype.every, but then again, you can’t really use this utility to type the every method, so perhaps a different name would make more sense.


Updated it to AllExtend!

@som-sm som-sm force-pushed the feat/add-every-type branch from a609966 to f931b95 Compare June 5, 2025 07:48
@som-sm som-sm changed the title Add Every type Add AllExtend type Jun 5, 2025
Comment on lines +106 to +108
export type IsExactOptionalPropertyTypesEnabled = [(string | undefined)?] extends [string?]
? false
: true;
Copy link
Collaborator Author

@som-sm som-sm Jun 5, 2025

Choose a reason for hiding this comment

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

Credits to @Emiyaaaaa for suggesting this type


expectType<Not<true>>(false);
expectType<Not<false>>(true);
// FIXME
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There's nothing to fix here, Not<boolean> should return boolean.

@som-sm som-sm requested a review from Copilot June 5, 2025 08:56

This comment was marked as resolved.

@sindresorhus sindresorhus merged commit c8c6d55 into main Jun 5, 2025
6 checks passed
@sindresorhus sindresorhus deleted the feat/add-every-type branch June 5, 2025 09:56
benzaria pushed a commit to benzaria/type-fest that referenced this pull request Jun 6, 2025
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.

4 participants