sindresorhus / type-fest

A collection of essential TypeScript types
Creative Commons Zero v1.0 Universal
13.64k stars 515 forks source link

DistributedOmit may not need to constraint the second type argument #866

Open tommytroylin opened 2 months ago

tommytroylin commented 2 months ago

since typescript omit is something like this

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

could we change the constraint extends KeysOfUnion<ObjectType> in DistributedOmit as same ?

Upvote & Fund

Fund with Polar

sindresorhus commented 2 months ago

Why?

tommytroylin commented 2 months ago

@sindresorhus

we were build a component wrapper which disallow passing some specific props directly

the Omit in typescript works great until some one come in with a union typed props

here is the demo


import type { DistributedOmit } from 'type-fest';

type DistributedOmitLoose<
  ObjectType,
  KeyType extends keyof any,
> = ObjectType extends unknown ? Omit<ObjectType, KeyType> : never;

type SomeComponentPropsTypeWithControl = {
  onChange: (value: any) => void;
  controllable: true;
};

type SomeComponentPropsTypeWithoutControl = {
  controllable: false;
};

type SomeComponentProps =
  | SomeComponentPropsTypeWithoutControl
  | SomeComponentPropsTypeWithControl;

// works
type Result1 = Omit<SomeComponentProps, 'value'>;

// works and exactly what i want
type Result2 =
  | Omit<SomeComponentPropsTypeWithControl, 'value'>
  | Omit<SomeComponentPropsTypeWithoutControl, 'value'>;

// loose constraint. works. same as Result2
type Result3 = DistributedOmitLoose<SomeComponentProps, 'value'>;

// DistributedOmit from package
// Type '"value"' does not satisfy the constraint 'keyof SomeComponentPropsTypeWithoutControl'
type Result4 = DistributedOmit<SomeComponentProps, 'value'>;

IMO, when omitting properties from a interface, there's no need to check if they were actually exist. That's why TS's Original Omit didn't check the 2nd type argument. (Just my opinion, not checked if it's right)

sindresorhus commented 2 months ago

I do agree that it would be nice to support this use-case. One downside is that it then would not be able to auto-complete the key.

sindresorhus commented 2 months ago

@henriqueinonhe Thoughts?

Nr9 commented 2 months ago

I have a similar issue with DistributedOmit

The simple following type does not work

type ReplaceKey<T, V> = T extends { key: string } ? DistributedOmit<T, 'key'> & { key: V } : T

I get the following error

TS2344: Type "key" does not satisfy the constraint KeysOfUnion<T>
medv commented 2 months ago
DistributedOmitLoose

This is fantastic, thank you. In a heavily abstracted layer of framework code, it's most often not possible to get autocompletion on Omit anyway. This is a great drop in replacement for DistributedOmit.