web-dev-qa-db-ja.com

TypeScript:タイプ/減算タイプからキーを削除します

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

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

Innercartプロップと0個以上の他のプロップを取る必要があります。 Wrapperは、cartClientプロップ(cartプロップを生成してInnerに渡すために使用)と、Inner受け入れるexceptcart

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

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

組み込みの減算タイプはありませんが、現在ハッキングできます。

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

遊び場でテスト

6
Adrian Leonhard

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">;
21
alter igel

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


この機能に対するさまざまな古いリクエスト( "outersection"タイプ減算タイプ )がありますが、実際には何も進行していません。

最近、マップされたタイプを追加して、これについてもう一度質問しました、そしてアンダースは 一般的な減算タイプの演算子を作成する計画はありませんが と言った、おそらくより制限されたバージョンが実装され、おそらく次のようなものになります- この提案

私は個人的に、Reactで作業しているときに非常によく似た状況に遭遇しましたが、残念ながら良い解決策を見つけることができませんでした。単純なケースでは、次のようなものを回避できます。

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

interface Inner extends BaseProps {
    cart: Cart;
}

interface Wrapper extends BaseProps {
    cartClient: Client;
}

しかし、これはextendsキーワードのセマンティックな乱用であることがほとんどです。そしてもちろん、InnerまたはBasePropsのタイプを制御しない場合、これはうまくいきません。

1
JKillian