I want to define a generic type ExcludeCart<T>
that is essentially T
but with a given key (in my case, cart
) removed. So, for instance, ExcludeCart<{foo: number, bar: string, cart: number}>
would be {foo: number, bar: string}
. Is there a way to do this in TypeScript?
Here's why I want to do this, in case I'm barking up the wrong tree: I'm converting an existing JavaScript codebase to TypeScript, which contains a decorator function called cartify
that takes a React component class Inner
and returns another component class Wrapper
.
Inner
should take a cart
prop, and zero or more other props. Wrapper
accepts a cartClient
prop (which is used to generate the cart
prop to pass to Inner
), and any prop that Inner
accepts, except cart
.
In other words, once I can figure out how to define ExcludeCart
, I want to do this with it:
function cartify<P extends {cart: any}>(Inner: ComponentClass<P>) : ComponentClass<ExcludeCart<P> & {cartClient: any}>
While there isn't a built-in subtraction type, you can currently hack it in:
In the question's case, you would do:
With TypeScript >= 2.6, you can simplify it to:
test it on the playground
Update: See Adrian's answer above for a solution to this question. I've left my answer here though since it still contains some useful links.
There are various old requests for this feature ("outersection" types, subtraction types), but none have really progressed.
Recently, with the addition of mapped types I asked about this again, and Anders said that while there's no plans to make a general subtraction type operator, a more limited version might be implemented, presumably looking something like this proposal.
I've personally run into quite similar situations to you when working with React, and unfortunately haven't been able to find any good solution. In a simple case, you can get away with something like:
but I almost find this to be a semantic abuse of the
extends
keyword. And of course, if you don't control the typings ofInner
orBaseProps
, then this won't work out.Since TypeScript 2.8 and the introduction of
Exclude
, It's now possible to write this as follows:Or alternatively, and more concisely, as:
For your usage, you could now write the following: