Lodashの_.omit
関数を単純なTypeScriptで複製したい。 omit
は、最初に来るオブジェクトパラメータの後に、パラメータを介して指定された特定のプロパティが削除されたオブジェクトを返す必要があります。
これが私の最善の試みです:
function omit<T extends object, K extends keyof T>(obj: T, ...keys: K[]): {[k in Exclude<keyof T, K>]: T[k]} {
let ret: any = {};
let key: keyof T;
for (key in obj) {
if (!(keys.includes(key))) {
ret[key] = obj[key];
}
}
return ret;
}
これは私にこのエラーを与えます:
Argument of type 'keyof T' is not assignable to parameter of type 'K'.
Type 'string | number | symbol' is not assignable to type 'K'.
Type 'string' is not assignable to type 'K'.ts(2345)
let key: keyof T
エラーの私の解釈はそれです:
Keyはkeyof T
であり、T
はオブジェクトであるため、keyはsymbol
、number
またはstring
にすることができます。
私はfor in
ループを使用しているため、keyはstring
のみにすることができますが、たとえば、配列で渡す場合、includes
はnumber
をとる可能性があります。おもう。つまり、ここに型エラーがあるということですか?
これが機能しない理由とそれを機能させる方法についての洞察は高く評価されています!
interface Omit {
<T extends object, K extends [...(keyof T)[]]>
(obj: T, ...keys: K): {
[K2 in Exclude<keyof T, K[number]>]: T[K2]
}
}
const omit: Omit = (obj, ...keys) => {
let ret = {} as {
[K in keyof typeof obj]: (typeof obj)[K]
};
let key: keyof typeof obj;
for (key in obj) {
if (!(keys.includes(key))) {
ret[key] = obj[key];
}
}
return ret;
}
便宜上、入力のほとんどをインターフェイスにプルしました。
問題は、K
がnionではなくTupleとして推論されている(正しい時制?)ことでした。したがって、それに応じてタイプ制約を変更しました。
[...(keyof T)[]] // which can be broke down to:
keyof T // a union of keys of T
(keyof T)[] // an array containing keys of T
[] // a Tuple
[...X] // a Tuple that contains an array X
次に、タプルK
を共用体に変換する必要があります(keyof T
からExclude
にするため)。これはK[number]
で行われます。これは自明のとおりです。T[keyof T]
と同じで、T
の値の結合を作成します。
キーのタイプを文字列[]に制限すると、機能します。しかし、それは良い考えではないようです。番号|シンボル[];
function omit<T, K extends string>(
obj: T,
...keys: K[]
): { [k in Exclude<keyof T, K>]: T[k] } {
let ret: any = {};
Object.keys(obj)
.filter((key: K) => !keys.includes(key))
.forEach(key => {
ret[key] = obj[key];
});
return ret;
}
const result = omit({ a: 1, b: 2, c: 3 }, 'a', 'c');
// The compiler inferred result as
// {
// b: number;
// }