Căutare TypeScript din literal de obiect
Am un literal de obiect astfel în Typescript:
const data={
a:'valueOfA',
b:'valueOfB,
...
}
Atunci trebuie să actualizez valorile în diferite locuri trecând obiectul și proprietatea de actualizat astfel:
function update(obj,prop){
...
}
update(data,'a');
Acest lucru funcționează, desigur, dar mi-ar plăcea să accesez proprietatea folosind notația cu punct și să profit de intellisense în IDE. Astfel, pot apela funcția în felul următor:
update(data,KeysOfData.a);
Am realizat o primă implementare care funcționează bine și oferă intellisense, dar mi se pare destul de urâtă și aș vrea să știu dacă există modalități mai bune de a obține rezultatul. Iată implementarea actuală:
type FormProps = {
firstName?: string,
lastName?: string,
email?: string
}
const formData: FormProps = {
firstName: '',
lastName: '',
email: ''
}
type FormItemName = keyof FormProps;
type FormItem = {
[key in FormItemName]: string
}
// Generates lookup object
const Fields: FormItem = Object.keys(formData).reduce<FormItem>((obj, field) => {
obj[field as FormItemName] = field;
return obj;
}, {} as any);
// Later call to update
update(formData,Fields.firstName);
Răspuns #1
Voi trata această întrebare ca pe una care întreabă cum să folosești genericele și keyof pentru a-ți face codul reutilizabil și a îmbunătăți siguranța tipurilor.
Prima sugestie: Soluția ta, dar folosind generice
Poți extrage implementarea ta astfel încât să o poți reutiliza pentru alte obiecte astfel:
// Generic reusable lookup type
type FieldLookup<T> = { [key in keyof T]: string }
// Generic reusable lookup generation function
function generateFieldLookup<T>(data: T): FieldLookup<T> {
return Object.keys(formData).reduce((obj, field) => {
obj[field as keyof T] = field;
return obj;
}, {} as FieldLookup<T>)
}
// Generates lookup object
const Fields = generateFieldLookup(formData)
// Later call to update
update(formData, Fields.firstName);
Totuși, ceea ce spune acest tip este că o proprietate a lui T este de asemenea o proprietate a obiectului de căutare care are ca valoare un anumit șir, un tip mai corect ar fi:
type FieldLookup<T> = { [key in keyof T]: key; }
function generateFieldLookup<T>(data: T): FieldLookup<T> {
return Object.keys(formData).reduce((obj, field) => {
const key = field as keyof T;
obj[key] = key;
return obj;
}, {} as FieldLookup<T>)
}
Acum, când vei trece cursorul peste Fields.firstName, vei vedea și valoarea exactă a tipului. Totuși, va apărea că undefined este o posibilitate. Asta pentru că nicăieri în tip nu se specifică că toate câmpurile sunt incluse în căutare.
Dacă acest lucru cauzează o problemă pentru tine oriunde în cod, pur și simplu fă Fields.firstName!
A doua sugestie: Tastează update
Dacă poți renunța la abilitatea IDE-ului de a-ți oferi sugestii când dai clic pe punct și vrei doar siguranță tip și sugestii prin trecerea cursorului peste funcție pentru a obține tipul dedus, poți să renunți la întreaga implementare și doar să scrii update astfel:
function update<T>(obj: T, prop: keyof T): void
// Later call to update
update(formData, 'firstName');
Rețineți că această sugestie nu exclude pe cea anterioară, puteți folosi ambele.
Dacă faci asta, va trebui să folosești versiunea mai avansată a implementării din prima sugestie, cu semnul exclamării, adică să faci:
// Generic reusable lookup type
type FieldLookup<T> = { [key in keyof T]: key }
function update<T>(obj: T, prop: keyof T): void
// Later call to update
update(formData, Fields.firstName!);
