次のようなユーティリティタイプをエクスポートするライブラリがあります。
type Action<Model extends object> = (data: State<Model>) => State<Model>;
このユーティリティタイプを使用すると、「アクション」として実行される関数を宣言できます。Model
アクションが動作するという一般的な引数を受け取ります。
次にdata
、「アクション」の引数に、エクスポートする別のユーティリティタイプを入力します。
type State<Model extends object> = Omit<Model, KeysOfType<Model, Action<any>>>;
State
ユーティリティ型は基本的に入ってくる取りModel
ジェネリックをして、タイプであるすべてのプロパティは、新しいタイプの作成Action
削除されましたが。
たとえば、ここには上記の基本的なユーザー土地の実装があります。
interface MyModel {
counter: number;
increment: Action<Model>;
}
const myModel = {
counter: 0,
increment: (data) => {
data.counter; // Exists and typed as `number`
data.increment; // Does not exist, as stripped off by State utility
return data;
}
}
上記は非常にうまく機能しています。👍
ただし、特に一般的なモデル定義が定義されているときに、一般的なモデルのインスタンスを生成するためのファクトリー関数と一緒に苦労しているケースがあります。
例えば;
interface MyModel<T> {
value: T; // 👈 a generic property
doSomething: Action<MyModel<T>>;
}
function modelFactory<T>(value: T): MyModel<T> {
return {
value,
doSomething: data => {
data.value; // Does not exist 😭
data.doSomething; // Does not exist 👍
return data;
}
};
}
上記の例data
では、doSomething
アクションが削除され、ジェネリックvalue
プロパティがまだ存在する場所に引数が入力されることを期待しています。ただし、これは当てはまりません。value
プロパティもState
ユーティリティによって削除されています。
これの原因は、T
型の制限/絞り込みが適用されていない一般的なものであり、型システムはAction
型と交差することを決定し、その後data
引数の型から削除することです。
この制限を回避する方法はありますか?私はいくつかの研究を行っており、それを除いて、私がそれを述べることT
ができる何らかのメカニズムがあると期待していた。つまり、ネガティブ型の制限。Action
想像してみてください:
function modelFactory<T extends any except Action<any>>(value: T): UserDefinedModel<T> {
しかし、その機能はTypeScriptには存在しません。
これを期待どおりに機能させる方法を誰かが知っていますか?
ここでのデバッグを支援するために、完全なコードスニペットがあります。
// Returns the keys of an object that match the given type(s)
type KeysOfType<A extends object, B> = {
[K in keyof A]-?: A[K] extends B ? K : never
}[keyof A];
// Filters out an object, removing any key/values that are of Action<any> type
type State<Model extends object> = Omit<Model, KeysOfType<Model, Action<any>>>;
// My utility function.
type Action<Model extends object> = (data: State<Model>) => State<Model>;
interface MyModel<T> {
value: T; // 👈 a generic property
doSomething: Action<MyModel<T>>;
}
function modelFactory<T>(value: T): MyModel<T> {
return {
value,
doSomething: data => {
data.value; // Does not exist 😭
data.doSomething; // Does not exist 👍
return data;
}
};
}
このコード例は、https://codesandbox.io/s/reverent-star-m4sdb?fontsize = 14で試すことができ ます。