私はLoadable<T>
という名前の汎用クラスを作成しています。 1つはstate
という名前で、ロード可能リソースの現在の状態を含みます。 2番目のものはdata
という名前で、ロード可能リソースの値が含まれています。
state
は"loading" | "loaded" | "error"
として定義されています。data
の現在の値に基づいてstate
を変更したいと思います。
たとえば、state
が"loading"
の場合、data
はnull
になります。これを行うために構文を把握することはできません。
次のように定義されているLoadableState<T, U>
という名前のtype
を作成しました。
type LoadableState<T, U> =
T extends "loaded" ? U :
T extends "loading" ? null :
T extends "error" ? string :
never;
T
が渡されたタイプ"loaded" | "loading" | "error"
でなければなりません。
この部分は動作しますが、これからdata
を定義しようとしていません。
export class Loadable<T> {
public state: "loaded" | "loading" | "error" = "loading";
public data: LoadableState<state, T>;
// ^^^^^ Cannot find name 'state`
}
TypesScriptは次のエラーをスローします。Cannot find name 'state'
私が試した他のもの:
public data: LoadableState<this.state, T>;
// Duplicate identified 'state'
public data: LoadableState<typeof this.state, T>;
// Cannot find name 'this'
public data: LoadableState<typeof state, T>;
// Cannot find name 'state'
public data: state extends "loaded" ? T :
state extends "loading" ? null :
state extends "error" ? string :
never;
// Cannot find name 'state'
これが実際に可能なかどうかはかなりありません。そうでなければ、この問題に対する別の解決策はありますか?
あるクラスプロパティのタイプが別のプロパティの値に依存する方法があるとは思わない(または少なくともきれいな方法ではありません)。
これらのプロパティの両方を単一のオブジェクトに組み合わせることをお勧めします。
type LoadState<T> = {
state: "loading",
} | {
state: "loaded",
data: T
} | {
state: "error",
data: string; // or maybe 'message'
}
export class Loadable<T> {
state: LoadState<T> = { state: "loading" }
}
_
クラスラッパーは実際には非常に便利ではありませんが、クラスをまったく使用しないことを検討するかもしれません。
このタイプを使用する場合、データにアクセスしようとする前に、TypeScriptはstate
をチェックすることを確認します。
function handleLoadState<T>(loadState: LoadState<T>) {
loadState.data // ERROR, can't access data, since it might not exist
if(loadState.state === "loaded")
loadState.data // okay
}
}
_
このパターンは 識別共用体 と呼ばれ、タイプスクリプトではかなり一般的に使用されています。