Typescript,如何將一個物件映射到另一個物件?
我有兩個物件,以及我的自訂地圖函數,用於將一個物件的屬性映射到另一個物件的值,例如:
const obj1 = {
host: 'clientNameHost',
pass: 'clientNamePass',
};
const obj2 = {
clientNamePass: '12345',
clientNameHost: 'http://localhost:3000',
};
const mapParams = <T, K>(source: T, params: K) => Object.entries(params)
.reduce((acc, [param, sourceProp]) => ({ ...acc, [param]: source[sourceProp] }), {});
mapParams(obj2, obj1) //{host: "http://localhost:3000", pass: "12345"}
我在努力嘗試輸入這個函數時遇到了困難。有沒有什麼方法可以正確地輸入 mapParams 函數?
答案#1
解決方法是縮小泛型類型,以顯示兩個參數中鍵與值之間的關係:
const obj1 = {
host: 'clientNameHost',
pass: 'clientNamePass',
} as const;
const obj2 = {
clientNamePass: '12345',
clientNameHost: 'http://localhost:3000',
} as const;
const mapParams = <T extends Record<string, any>, K extends keyof T, P extends Record<T[K], any>>(source: T, params: P) => Object.entries(params)
.reduce((acc, [param, value]) => ({ ...acc, [param]: source[value as T[K]] }), {});
console.log(mapParams(obj1, obj2)) //{host: "http://localhost:3000", pass: "12345"}
主要部分:
T extends Record<string, any>的第一種類型是具有字串鍵的 RecordK extends keyof T代表T的鍵P extends Record<T[K], any>關鍵部分 - 我們想要一個物件,其鍵將等於T中的值- 為了正確推斷縮小後的類型,新增了
as const
上述類型在第一個參數值與第二個參數鍵之間建立了關聯。
附言:抱歉把參數的順序弄反了。
答案#2
當我撰寫函數時,我最關心的是參數和返回類型。
你可以這樣輸入參數:
<InputProps, TargetProps extends Record<keyof TargetProps, keyof InputProps>>(
source: InputProps,
params: TargetProps
) => ...
如果第二個物件與第一個不匹配,Typescript 會報錯。
對於返回值,你可以定義如下的工具類型:
type MapFrom<A, B> = Record<keyof A, B[keyof B]>;
透過使用 Object.prototype.entries 型別參數,我們可以避免必須對 sourceProp 進行轉型。
為了保持函數簽名,我們需要在 reduce 中斷言 initialValue 的類型。
我也使用 const 斷言來賦予物件字面量唯讀屬性
這是完整的結果:
type MapFrom<A, B> = Record<keyof A, B[keyof B]>;
const obj1 = {
host: "clientNameHost",
pass: "clientNamePass"
} as const;
const obj2 = {
clientNamePass: "12345",
clientNameHost: "http://localhost:3000"
} as const;
const mapParams = <InputProps, TargetProps extends Record<keyof TargetProps, keyof InputProps>>(
source: InputProps,
params: TargetProps
) =>
Object.entries<keyof InputProps>(params).reduce(
(acc, [param, sourceProp]) => ({
...acc,
[param]: source[sourceProp]
}),
{} as MapFrom<TargetProps, InputProps>
);
const obj3 = mapParams(obj2, obj1);
你可以在這裡試試看。
