javascript - Hur man kopierar värden från endast en delmängd av objektets egenskaper till ett annat befintligt objekt i TypeScript
Låt oss säga att jag har ett befintligt objekt obj1={a: 'A', b: 'B', c: 'C', d: 'D'}
Jag har ett annat objekt något som obj2={b: 'B2', c: 'C2', d: 'D2', e: 'E2'}
Nu vill jag selektivt kopiera värdena från bara några egenskaper från obj2 till obj1, för resten av egenskaperna i obj1 vill jag att de förblir oförändrade.
Nu, säg att jag vill kopiera värdena av egenskaperna b och d. Jag skulle vilja göra något som
obj1 = {a: 'A', b: 'B', c: 'C', d: 'D'};
obj2 = {b: 'B2', c: 'C2', d: 'D2', e: 'E2'};
copyPropertyvalues(
obj2, // source
obj1, // destination
[obj2.b, obj2.d] // properties to copy >> see clarification below
); // should result in obj1 = {a: 'A', b: 'B2', c: 'C', d: 'D2'}
Hur skriver jag den här metoden? Observera att jag inte heller vill tillhandahålla listan över egenskaper som strängar, eftersom jag vill ha så mycket kompileringstidssäkerhet som möjligt.
Så de grundläggande frågorna här är:
- Kopiera bara några egenskapsvärden från ett objekt
- Kopiera till ett befintligt objekt & inte skapa ett nytt
- Behåll andra egenskapsvärden i destinationsobjektet
- Undvik strängar för egenskapsnamn (som
'b', 'd') och utnyttjaTypeScript-säkerhet så mycket som möjligt
Förtydligande baserat på kommentar:
När jag säger obj2.b eller liknande i (pseudo) kodexempel
- Jag menar inte bokstavligen
obj2.b - Snarare något sätt att kontrollera vid kompileringstid att
bfaktiskt är en egenskap på typen avobj2
Svar #1
Mitt förslag för copyPropertyvalues() skulle vara något i stil med detta:
function copyPropertyvalues<T, K extends keyof T>(s: Pick<T, K>, d: T, ks: K[]) {
ks.forEach(k => d[k] = s[k]);
return d;
}
Funktionen är generisk i typen T av destinationsobjektet och typen K av nyckelnamn som du ska kopiera från källan till destinationsobjektet. Jag antar att du vill kräva att egenskaperna du kopierar från källan ska vara av samma typ som egenskaperna som redan finns i destinationen; till exempel skulle du inte kopiera egenskapen "a" från en källa av typen {a: number} till en destination av typen {a: string}, eftersom du då skulle skriva ett number till en string och kränka typen i destinationen.
Observera att vi inte behöver att källobjektet är exakt T; det behöver bara stämma överens med T på alla nycklar i K. Det vill säga, vi säger bara att det måste vara Pick<T, K> med hjälp av verktygstypen Pick<T, K>.
Och notera att vi definitivt skickar in en array av nyckelsträngar, vilket kompilatorn kommer att härleda inte bara som string, utan specifikt som en union av strängliteraltyper som är en delmängd av keyof T (använder keyof-typoperatören för att få en union av de kända nycklarna i T). Så om du skickar in ["b", "d"], kommer kompilatorn att härleda det som typen Array<"b" | "d"> och inte bara Array<string>. Detta ger dig den typ säkerhet du letar efter, utan att behöva oroa dig för något som nameof som inte existerar i JavaScript (och inte kommer att existera i TypeScript förrän det gör det, se microsoft/TypeScript#1579).
Okej, låt oss prova det:
copyPropertyvalues(
obj2, // source
obj1, // destination
["b", "d"] // properties to copy
);
console.log(obj1)
/* {
"a": "A",
"b": "B2",
"c": "C",
"d": "D2"
} */
Ser ut som det beter sig som du vill. Och om du sätter fel nycklar där får du kompileringstidsfel:
copyPropertyvalues(
obj2, // error!
obj1,
["a"]
)
copyPropertyvalues(
obj2,// error!
obj1,
["z"]
)
Playground-länk till kod
