TypeScript: remove key from type/subtraction type
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.
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
Update for TypeScript 3.5: The Omit<Type, Keys>
utility type is now available. Please see Mathias' answer for an example usage.
Old Answer: 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">;
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.