3

關鍵我想定義泛型類型ExcludeCart<T>這基本上是T但刪除的指定鍵(在我的情況,cart)。因此,例如,ExcludeCart<{foo: number, bar: string, cart: number}>將是{foo: number, bar: string}。有沒有辦法在TypeScript中做到這一點?打字稿:刪除從類型/減法型

這就是爲什麼我想這樣做,以防萬一我吠叫錯誤的樹:我將現有的JavaScript代碼庫轉換爲TypeScript,其中包含一個名爲cartify的裝飾器函數,它需要React組件類Inner並返回另一個組件類Wrapper

Inner應該採取cart道具,以及零個或多個其他道具。 Wrapper接受cartClient支柱(其被用於生成cart支柱傳遞到Inner),以及任何其支撐接受Inner除了cart

換句話說,一旦我能想出如何定義ExcludeCart,我想用它做:

function cartify<P extends {cart: any}>(Inner: ComponentClass<P>) : ComponentClass<ExcludeCart<P> & {cartClient: any}> 
+1

還沒有,但有一個建議 - https://github.com/Microsoft/TypeScript/issues/4183。另見https://github.com/Microsoft/TypeScript/issues/12215 – artem

回答

3

雖然沒有內置減法類型,您目前可以破解它:

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

隨着打字稿> = 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

+0

這太棒了,謝謝!我曾嘗試過的所有'Omit'實現都不適用於泛型,但這些實現。 –

+0

非常酷!阿德里安,你開發了這個,還是你發現它在別的地方?如果來自其他地方,您是否可以鏈接到該來源?我試圖查看你的答案,看它是否有任何限制或任何其他相關的討論。我也鏈接到你的答案,因爲它似乎很好用 – JKillian

+1

@JKillian不,我不記得我從哪裏得到它,但在相應的TS問題上討論了各種變體,例如https:// github .com/Microsoft/TypeScript/issues/12215#issuecomment-307871458 –

1

更新:爲解決這個問題,見Adrian's answer above。我已經在這裏留下了我的答案,因爲它仍然包含一些有用的鏈接。


有此功能("outersection" 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的類型,那麼這將無法解決。

+1

謝謝!不幸的是,我不能真正做你所建議的,因爲我希望能夠只鍵入'MyComponent = cartify(MyComponent)'(或@@@@@@@@@@@@@@@@@@@@@@@@@ @包裝組件的正確類型。而且它是一個可重用的庫,所以我絕對無法提前預測'Inner'。 –