Skip to content

Except: Enhancing parameter‌ types#1425

Draft
Emiyaaaaa wants to merge 3 commits into
sindresorhus:mainfrom
Emiyaaaaa:feat/Except
Draft

Except: Enhancing parameter‌ types#1425
Emiyaaaaa wants to merge 3 commits into
sindresorhus:mainfrom
Emiyaaaaa:feat/Except

Conversation

@Emiyaaaaa

Copy link
Copy Markdown
Collaborator

When the 2nd input param KeysType is clearly defined, keyof ObjectType can correctly constrain and suggest parameter options. However, when the input type is ambiguous due to generics, keyof ObjectType prevents the parameter from passing. LiteralUnion can relax the strict input type, and still maintain the parameter suggestions.

If there are ok, I can fix similar problems in other PRs.

@Emiyaaaaa Emiyaaaaa requested review from Copilot, sindresorhus and som-sm and removed request for Copilot and som-sm May 15, 2026 02:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot wasn't able to review any files in this pull request.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Emiyaaaaa Emiyaaaaa requested a review from Copilot May 15, 2026 02:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot wasn't able to review any files in this pull request.

@Emiyaaaaa Emiyaaaaa requested a review from som-sm May 15, 2026 02:56
@sindresorhus

Copy link
Copy Markdown
Owner

I think this changes the contract too much.

Except is documented as stricter than Omit: it should only allow keys that actually exist, so typos and rename mistakes are caught. With this PR, arbitrary property keys are accepted because the key constraint includes PropertyKey.

I agree with fixing the generic conditional type case, but I don't think the fix should drop the strict key guarantee for normal object types. That guarantee is one of the main reasons this type exists, becuase otherwise it gets much closer to Omit.

@som-sm

som-sm commented May 15, 2026

Copy link
Copy Markdown
Collaborator

@Emiyaaaaa In cases like these, simply taking an intersection would silence the error:

import type {Except} from "type-fest";

type GenericType<T> = T extends string ? {
	foo: T;
	bar: string;
} : {
	baz: T;
};

type GenericTypeExcept<T> = Except<GenericType<T>, 'foo' & keyof GenericType<T>>; // ✅ Works

type G1 = GenericTypeExcept<string>;
//=> { bar: string; }

type G2 = GenericTypeExcept<number>;
//=> { baz: number; }

This is better IMO because you're acknowledging that the second argument needs to be keyof T, and if it's not, the intersection would make it never and Except<T, never> is basically a no-op.


Moreover, in the above example, the compiler rightly complains because 'foo' is not a key of {baz: T}. If both branches had 'foo', the compiler would recognise this and stop complaining. Refer:

import type {Except} from "type-fest";

type GenericType<T> = T extends string ? {
	foo: T;
	bar: string;
} : {
	foo: string; // <--- Added `foo` here too
	bar: T;
};

type GenericTypeExcept<T> = Except<GenericType<T>, 'foo'>; // ✅ Works

type G1 = GenericTypeExcept<string>;
//=> { bar: string; }

type G2 = GenericTypeExcept<number>;
//=> { bar: number; }

@Uygniqoar

Copy link
Copy Markdown

@sindresorhus @som-sm Let's see the simpler case:

type A = { foo: string } | { bar: number };

type B = Except<A, 'foo'> // should throw error or not?

Is the union type included in the design of Except?

@som-sm

som-sm commented May 18, 2026

Copy link
Copy Markdown
Collaborator

Is the union type included in the design of Except?

@Uygniqoar Except is meant to work with union types, but it only allows keys that are present across all union members, like Except<{a: 1; b: 2} | {b: 3; c: 4}, 'b'> -> {a: 1} | {c: 4}.

You can use the DistributedOmit type in case you want to omit keys that are not present across all union members.

@som-sm

som-sm commented May 21, 2026

Copy link
Copy Markdown
Collaborator

@Emiyaaaaa Shall we close this then?

@Emiyaaaaa Emiyaaaaa marked this pull request as draft May 22, 2026 09:53
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.

Except not playing well conditional types and/or infer

5 participants