40

ExcludeCart<T>基本的にはジェネリック型を定義したいのですTが、特定のキー (私の場合はcart) が削除されています。したがって、たとえば、ExcludeCart<{foo: number, bar: string, cart: number}>になります{foo: number, bar: string}。TypeScriptでこれを行う方法はありますか?

間違ったツリーを吠えている場合に備えて、これを行いたい理由は次のとおりです。既存の JavaScript コードベースを TypeScript に変換しています。これにcartifyは、React コンポーネント クラスを受け取り、Inner別のコンポーネント クラスを返すというデコレータ関数が含まれていますWrapper

Innercartprops と 0 個以上のその他の propsを取る必要があります。Wrapperはprop (に渡す prop をcartClient生成するために使用される) と、を除く、受け入れるすべての prop を受け入れます。cartInnerInner cart

言い換えれば、 を定義する方法がExcludeCartわかったら、それを使って次のことを行いたいと思います。

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

6 に答える 6

13

組み込みの減算タイプはありませんが、現在、次のようにハックできます。

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

プレイグラウンドでテストする

于 2017-12-04T22:34:46.237 に答える
2

この結果を得るための別の非常に簡単な方法があります

タイプスクリプトでタイプを組み合わせる場合、タイプ「決して」はすべてよりも優先されます。

タイプを簡単に作成できます。

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

または、タイプを作成せずに

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

これは Adrian のソリューションより一般的ではありませんが、複雑さが必要ない場合は少し単純です。

于 2019-08-05T17:18:45.343 に答える
1

更新:この質問の解決策については、上記の Adrian の回答を参照してください。ただし、いくつかの有用なリンクがまだ含まれているため、ここに回答を残しました。


この機能については以前からさまざまな要望 ( 「outersection」タイプ減算タイプ) がありましたが、実際に進んだものはありません。

最近、マップされた型の追加でこれについて再度尋ねたところ、Anders は、一般的な減算型の演算子を作成する計画はありませんが、おそらくこの提案のようなものに見える、より限定されたバージョンが実装される可能性があると述べました。

個人的に React を使用しているときに、あなたとよく似た状況に遭遇しましたが、残念ながら、適切な解決策を見つけることができませんでした。単純なケースでは、次のような方法で回避できます。

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

interface Inner extends BaseProps {
    cart: Cart;
}

interface Wrapper extends BaseProps {
    cartClient: Client;
}

extendsしかし、これはキーワードの意味論的乱用であることがほとんどわかります。もちろん、Innerまたはの入力を制御しないBasePropsと、これはうまくいきません。

于 2017-01-05T05:15:58.150 に答える