TypeScript: remove key from type/subtraction type

typescript pick example
typescript type
typescript return type
typescript dictionary type
typescript multiple types
typescript type check
typescript infer generic type
typescript

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:

type Sub0<
    O extends string,
    D extends string,
> = {[K in O]: (Record<D, never> & Record<string, K>)[K]}

type Sub<
    O extends string,
    D extends string,
    // issue 16018
    Foo extends Sub0<O, D> = Sub0<O, D>
> = Foo[O]

type Omit<
    O,
    D extends string,
    // issue 16018
    Foo extends Sub0<keyof O, D> = Sub0<keyof O, D>
> = Pick<O, Foo[keyof O]>

In the question's case, you would do:

type ExcludeCart<T> = Omit<T, 'cart'>

With TypeScript >= 2.6, you can simplify it to:

/**
 * for literal unions
 * @example Sub<'Y' | 'X', 'X'> // === 'Y'
 */
export type Sub<
    O extends string,
    D extends string
    > = {[K in O]: (Record<D, never> & Record<string, K>)[K]}[O]

/**
 * Remove the keys represented by the string union type D from the object type O.
 *
 * @example Omit<{a: number, b: string}, 'a'> // === {b: string}
 * @example Omit<{a: number, b: string}, keyof {a: number}> // === {b: string}
 */
export type Omit<O, D extends string> = Pick<O, Sub<keyof O, D>>

test it on the playground

Subtraction types · Issue #4183 · microsoft/TypeScript · GitHub, This feature would require a new negated type like number ~ string which Unable to void object keys using `strictNullChecks` option #8904 while the subtraction should remove some more, rather than adding null back in. Note: The Exclude type is a proper implementation of the Diff type suggested here. We’ve used the name Exclude to avoid breaking existing code that defines a Diff, plus we feel that name better conveys the semantics of the type. We did not include the Omit<T, K> type because it is trivially written as Pick<T, Exclude<keyof T, K>>.

Since TypeScript 2.8 and the introduction of Exclude, It's now possible to write this as follows:

type Without<T, K> = {
    [L in Exclude<keyof T, K>]: T[L]
};

Or alternatively, and more concisely, as:

type Without<T, K> = Pick<T, Exclude<keyof T, K>>;

For your usage, you could now write the following:

type ExcludeCart<T> = Without<T, "cart">;

Add support for literal type subtraction · Issue #12215 · microsoft , If you use this pattern to "remove" props, the typechecker will still complain if you omit them when using a component: type Omit<A, B extends  TypeScript: remove key from type/subtraction type. 12. Reactj, typescript Property 'setState' is missing in type. 3. Type checking styled-components props in

there is another very simple way to have this result

When combining type in typescript, the type "never" have higher priority to everything.

You can simply create a type:

type noCart<T> = T & {cart : never}

Or, without creating type

function removeCart<T>(obj : T) : T & {cart : never} {
    if("cart" in obj) {
        delete (obj as T & {cart : any}).cart;
    }
    return <T & {cart : never}> obj;
}

This is less generic than the solution of Adrian, but a bit simpler when we don't need the complexity.

TypeScript: remove key from type/subtraction type - reactjs - html, 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,​  (That string-key constraint is important because objects in TypeScript can currently only use strings or numbers as keys; whereas union types can be all sorts of things.) Apart from that constraint on the union, though, we can basically just substitute a generic type parameter U , for “union,” where we had StateUnion before.

While this has been correctly answered, I wanted to point out that TypeScript 3.5 did add an Omit<T, E> type.

type NoCart = Omit<{foo: string, bar: string, cart: number}, "cart">;

This results in the {foo: string, bar: string} type.

Utility Types · TypeScript, Constructs a type by picking all properties from T and then removing K . Example #. interface Todo { title: string; description: string; completed: boolean  Instead, we'll require that the key actually exists on the type of the object that is passed in: function prop<T, K extends keyof T>(obj: T, key: K) { return obj[key]; } TypeScript now infers the prop function to have a return type of T[K], a so-called indexed access type or lookup type. It represents the type of the property K of the type T.

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:

interface BaseProps {
    foo: number;
    bar: number;
}

interface Inner extends BaseProps {
    cart: Cart;
}

interface Wrapper extends BaseProps {
    cartClient: Client;
}

but I almost find this to be a semantic abuse of the extends keyword. And of course, if you don't control the typings of Inner or BaseProps, then this won't work out.

Advanced Types · TypeScript, Optional parameters and properties; Type guards and type assertions return this.value; } } function getRandomPadder() { return Math.random() < 0.5 ? new or undefined , you can use the type assertion operator to manually remove them. interface Dictionary<T> { [key: string]: T; } let keys: keyof Dictionary<number>;  There is a way, requiring TypeScript 2.8's Conditional Types. It is based on the fact that 'a' extends string but string doesn't extends 'a' interface Foo { [key: string]: any; bar(): void; } type KnownKeys<T> = { [K in keyof T]: string extends K ? never : number extends K ? never : K } extends { [_ in keyof T]: infer U } ?

Notes on TypeScript: Pick, Exclude and Higher Order Components , Tagged with react, typescript, types. To tell TypeScript how our generic rest types are structured we need to remove all Exclude removes specific keys: type by spreading the generic props and removing the initialValue :. How to subtract one year from a Date type in Angular 2? Browse other questions tagged typescript angular How to get value typed by keyboard from Angular

The Definitive TypeScript Handbook, TypeScript is a statically-typed superset of JavaScript which aims to ease the development of large javascript TypeScript allows us to use more than one data type for a property. The keyof operator queries the set of keys for a given type. Exclude allows you to remove certain types from another type. It just so happens that TypeScript has something called a type guard. A type guard is some expression that performs a runtime check that guarantees the type in some scope. Using type predicates # To define a type guard, we simply need to define a function whose return type is a type predicate:

Mapped Type Modifiers in TypeScript, With TypeScript 2.8, mapped types have gained the ability to add or it was only possible to add modifiers to properties, but not remove them. Our Partial<T> type uses the keyof operator to determine all property keys that T  I would like to subtract days from the current date in TypeScript. For example, if the current date is October 1st, 2017, I would like to subtract 1 day to get September 30th, 2017, or if I want to subtract 3 days I would get September 28th etc. This is what I have so far, the result is I received December 31st, 1969.

Comments
  • Not yet, but there's a suggestion - github.com/Microsoft/TypeScript/issues/4183. See also github.com/Microsoft/TypeScript/issues/12215
  • This is great, thanks! All of the previous implementations of Omit that I'd tried didn't work on generics, but these ones do.
  • Very cool! Adrian, did you develop this, or did you find it somewhere else? If it's from somewhere else, can you link to that source? I was trying to look into your answer to see if it had any limitations or any other relevant discussion about it. I've also linked to your answer from mine because it seems to work well
  • @JKillian no, I can't remember where I got it from, but various variants are discussed on the corresponding TS issue, for example github.com/Microsoft/TypeScript/issues/…
  • I remember going through that exact thread and trying all the variants there around the time I posted this question, and all of the ones I tried didn't work for generics (as in, you could go Omit<T, 'foo'> where T was some concrete type, but something like function myfunc<T extends {foo: any}>(in: T) : Omit<T, 'foo'> would break with rather confusing errors). So I'm not sure if it's a different way of defining Omit that popped up later or an improvement/bugfix in TS, but I think your answer was correct at the time it was posted, @JKillian :)
  • This works pretty good. One thing I noticed was that if T has types that are optional, after using Without they are all required. Do you know why that is?
  • The docs also mention that type Omit<T, K> = Pick<T, Exclude<keyof T, K>> will also work, in the 2.8 release notes (down the bottom of the linked section). This version of Omit seems to work as expected with optional members too.
  • This is a good answer, I couldn't figure out how to scale it to multiple keys. I took an attempt at a more direct use of exclude in another answer. That approach scales rather easily.
  • Thanks for that! Unfortunately I can't really do what you're suggesting, because I want to be able to just type MyComponent = cartify(MyComponent) (or @cartify↵class MyComponent… once that syntax lands) and have TypeScript automatically infer the correct type for the wrapped component. And it's a reusable library, so I definitely can't predict Inner ahead of time either.
  • I believe simply Exclude<{ foo: number, bar: string, cart: number }, "cart"> will do the trick.
  • @Mathias that doesn't work in my testing
  • You're right! I was thinking Omit<{foo: number, bar: string, card: number}, "cart"> which achieves the correct result. Again. thanks for double checking! Should I delete the comment above?
  • Oh neat. I will have to try that out. Up to you on the comment.