TypeScript:从类型/减法类型中删除键

时间:2017-01-05 01:43:12

标签: reactjs generics typescript decorator higher-order-components

我想定义一个基本类型ExcludeCart<T>,它基本上是T,但是删除了给定键(在我的情况下,cart)。因此,例如,ExcludeCart<{foo: number, bar: string, cart: number}>将是{foo: number, bar: string}。有没有办法在TypeScript中执行此操作?

这就是我想要这样做的原因,以防我咆哮错误的树:我将现有的JavaScript代码库转换为TypeScript,其中包含一个名为{{1的装饰器函数获取React组件类cartify并返回另一个组件类Inner

Wrapper应该使用Inner道具,以及零个或多个其他道具。 cart接受Wrapper道具(用于生成传递给cartClient的{​​{1}}道具),以及cart接受的任何道具,除了 Inner

换句话说,一旦我弄清楚如何定义Inner,我想用它来做:

cart

6 个答案:

答案 0 :(得分:27)

自从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">;

答案 1 :(得分:7)

虽然没有内置的减法类型,但您现在可以将其破解为:

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

在问题的情况下,你会这样做:

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

使用TypeScript&gt; = 2.6,您可以将其简化为:

/**
 * 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

答案 2 :(得分:2)

还有另一种非常简单的方法来获得此结果

在打字稿中组合类型时,“从不”类型对所有内容都具有更高的优先级。

您可以简单地创建一个类型:

$array = [1,2,3,4,15,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,22,42,33,34,35,36,37,38,11,10];

$max = array_map('max', array_chunk($array, 10));

或者,不创建类型

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

与Adrian的解决方案相比,它的通用性较差,但是在我们不需要复杂性的情况下,它要简单一些。

答案 3 :(得分:2)

尽管已正确回答此问题,但我想指出TypeScript 3.5确实添加了Omit<T, E>类型。

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

这将导致{foo: string, bar: string}类型。

答案 4 :(得分:1)

更新:有关此问题的解决方案,请参阅Adrian's answer above。我已经在这里留下了答案,因为它仍然包含一些有用的链接。

此功能有各种旧请求("outersection" typessubtraction types),但没有一个真正有进展。

最近,通过添加映射类型,我再次询问了这一点,Anders说while there's no plans to make a general subtraction type operator,可能会实现更有限的版本,大概看起来像this proposal

在与React合作时,我个人遇到了非常类似的情况,不幸的是,我们找不到任何好的解决方案。在一个简单的例子中,你可以逃脱:

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

interface Inner extends BaseProps {
    cart: Cart;
}

interface Wrapper extends BaseProps {
    cartClient: Client;
}

但我几乎发现这是对extends关键字的语义滥用。当然,如果你不控制InnerBaseProps的类型,那么这不会成功。

答案 5 :(得分:1)

  

例如,ExcludeCart <{foo:number,bar:string,cart:number}>将是{foo:number,bar:string}

您可以使用Exclude语法直接执行此操作:

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