TypeScript: remove key from type / subtraction

I want to define a generic type ExcludeCart<T>that is essentially deleted Tbut with the specified key (in my case cart). So, for example, it ExcludeCart<{foo: number, bar: string, cart: number}>will be {foo: number, bar: string}. Is there a way to do this in TypeScript?

That's why I want to do this if I imitate the wrong tree: I convert the existing JavaScript code base to TypeScript, which contains a decorator function called cartifythat takes a React component class Innerand returns a different component class Wrapper.

Innermust take cartprop, and zero or more other details. Wrapperaccepts cartClientprop (which is used to generate cartprop to go to Inner), and any support it Inneraccepts except cart.

In other words, as soon as I can determine how to determine ExcludeCart, I want to do this with it:

function cartify<P extends {cart: any}>(Inner: ComponentClass<P>) : ComponentClass<ExcludeCart<P> & {cartClient: any}>
+13
source share
5 answers

Although the built-in type of subtraction does not exist, it can currently be hacked as follows:

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 this 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>>

check it out on the playground

+8
source

TypeScript 2.8 Exclude, :

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

, , :

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

:

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

: . . , , .


( "outersection" , ), .

, , , , .

React , , . - :

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

interface Inner extends BaseProps {
    cart: Cart;
}

interface Wrapper extends BaseProps {
    cartClient: Client;
}

extends. , , Inner BaseProps, .

+1

So, for instance, ExcludeCart<{foo: number, bar: string, cart: number}> would be {foo: number, bar: string}

You can use the Exclude syntax to do this directly:

Exclude<{foo: number, bar: string, cart: number}, { cart: number}>
+1
source

there is another very simple way to get this result

When combining a type in typewritten text, the type never has a higher priority over everything.

You can simply create a type:

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

Or without creating a 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 universal than Adrian’s solution, but a little easier when we don’t need complexity.

0
source

Source: https://habr.com/ru/post/1692682/


All Articles