javascript - Typescriptで特定の「keyof」パラメータの型を取得する方法は?
私はオブジェクトを別のオブジェクトに変換するためのアダプタスキーマを定義したいです。
export type AdapterSchema<Source, Destination> = {
[key in keyof Partial<Source>]: {
target: keyof Destination;
convert: (source: Source[key]) => Destination[keyof Destination];
};
};
プロパティの値をターゲットプロパティの値に変換する変換関数を追加することが可能であるべきです。
interface Foo {
a : string;
}
interface Bar {
b : number;
c : string;
}
const schema : AdapterSchema<Foo,Bar> = { a : {target: 'b', convert: (value) => 'x'}}
私はここでコンパイラにエラーを出してほしいです。なぜなら 'x' は number 型ではないからです。私の型は少なくとも少し型安全ですが、Bar の型だけが許可されているので、エラーは発生しません。ただし、Bar には string 型のプロパティもあるため、エラーは投げられません。
これはより型安全にすることができますか?
よろしくお願いします。
回答 #1
AdapterSchema<S, D>を変更して、各プロパティがD型の各キーKDに対して異なる可能性のあるtarget/convertペアのユニオンになるようにしたいです。
つまり、AdapterSchema<S, D> が何であれ、AdapterSchema<Foo, Bar> が次のように評価されることを望んでいるということです:
type ASFB = AdapterSchema<Foo, Bar>;
/* type ASFB = {
a?: {
target: "b";
convert: (source: string) => number;
} | {
target: "c";
convert: (source: string) => string;
} | undefined;
} */
これはあなたのバージョンを変更することで行えます(少し書き直していますが、同じです):
type OrigAdapterSchema<S, D> = {
[KS in keyof S]?: {
target: keyof D;
convert: (source: S[KS]) => D[keyof D];
};
};
以下のバージョンへ:
type AdapterSchema<S, D> = {
[KS in keyof S]?: ({ [KD in keyof D]-?: {
target: KD;
convert: (source: S[KS]) => D[KD];
} }[keyof D]);
}
これは、各キー KD が target を KD とし、convert の戻り値の型が D[KD] となるプロパティを持つマップ型を構築し、その後すぐに keyof D でインデックスしてプロパティのユニオンを得ることで動作します。
これで、AdapterSchema<Foo, Bar> が目的の型であることを確認できます。そして、コンパイラは期待通りに動作します:
const badSchema: AdapterSchema<Foo, Bar> = {
a: { target: 'b', convert: (value) => 'x' } // error!
// ~~~~~~ <-- b is not assignable to c
}
const schema: AdapterSchema<Foo, Bar> = {
a: {
target: "b",
convert: v => v.length
}
}; // okay
(この解決策は必ずしもAdapterSchema<S, D>がDのすべてのプロパティを実際に生成することを強制するものではないことに注意してください。例えば、{}はAdapterSchema<Foo, Bar>として許容されるものであり、またはSの各プロパティがDの同じプロパティにマッピングされる場合もあります。しかし、あなたの質問はこれに関するものではないので、この点に対する回答はここでは範囲外となります。)
コードへのプレイグラウンドリンク
