基本的にT
であるが、指定されたキー(私の場合はcart
)が削除されたジェネリック型ExcludeCart<T>
を定義したいと思います。したがって、たとえば、ExcludeCart<{foo: number, bar: string, cart: number}>
は{foo: number, bar: string}
になります。 TypeScriptでこれを行う方法はありますか?
間違ったツリーを起動した場合に備えて、これを実行する理由は次のとおりです。既存のJavaScriptコードベースを、Reactを受け取るcartify
というデコレータ関数を含むTypeScriptに変換しています。コンポーネントクラスInner
を返し、別のコンポーネントクラスWrapper
を返します。
Inner
はcart
プロップと0個以上の他のプロップを取る必要があります。 Wrapper
は、cartClient
プロップ(cart
プロップを生成してInner
に渡すために使用)と、Inner
受け入れるexceptcart
。
言い換えれば、ExcludeCart
の定義方法がわかったら、それを使ってこれを実行したいと思います。
function cartify<P extends {cart: any}>(Inner: ComponentClass<P>) : ComponentClass<ExcludeCart<P> & {cartClient: any}>
組み込みの減算タイプはありませんが、現在ハッキングできます。
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>>
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">;
更新:この質問の解決策については、 上記のエイドリアンの回答 を参照してください。いくつかの有用なリンクがまだ含まれているので、ここに私の答えを残しました。
この機能に対するさまざまな古いリクエスト( "outersection"タイプ 、 減算タイプ )がありますが、実際には何も進行していません。
最近、マップされたタイプを追加して、これについてもう一度質問しました、そしてアンダースは 一般的な減算タイプの演算子を作成する計画はありませんが と言った、おそらくより制限されたバージョンが実装され、おそらく次のようなものになります- この提案 。
私は個人的に、Reactで作業しているときに非常によく似た状況に遭遇しましたが、残念ながら良い解決策を見つけることができませんでした。単純なケースでは、次のようなものを回避できます。
interface BaseProps {
foo: number;
bar: number;
}
interface Inner extends BaseProps {
cart: Cart;
}
interface Wrapper extends BaseProps {
cartClient: Client;
}
しかし、これはextends
キーワードのセマンティックな乱用であることがほとんどです。そしてもちろん、Inner
またはBaseProps
のタイプを制御しない場合、これはうまくいきません。