Eroare Typescript la convertirea unui tip într-altul
Am o funcție care formatează niște date de la un tip la altul. Practic schimbă niște majuscule și împachetează câmpurile.
Acesta este codul meu:
const formatData = (data: Login): LoginFormatted => {
return {
Date: data.date,
UserInfo: {
name: data.user.name,
email: data.user.email
},
...data.otherFields
};
};
const doThat = (data: Login) => {
const dataFormatted = formatData(data);
return dataFormatted;
};
const dataFormatted = doThat({
date: "2000-12-01",
user: {
name: "Mary",
email: "[email "
},
otherFields: { lastname: "Snow", city: "Berlin" }
});
Și tipurile mele:
export type Login = {
date: string;
user: {
name: string;
email: string;
};
otherFields?: { [key: string]: string };
};
export type LoginFormatted = {
Date: string;
UserInfo: {
name: string;
email: string;
};
} & { [key: string]: string };
AICI codul funcțional
Primesc o eroare TypeScript în formatData:
Tipul '{ Date: string; UserInfo: { name: string; email: string; }; }' nu poate fi atribuit tipului 'LoginFormatted'. Tipul '{ Date: string; UserInfo: { name: string; email: string; }; }' nu poate fi atribuit tipului '{ [cheie: string]: string; }'. Proprietatea 'UserInfo' este incompatibilă cu semnătura indexului. Tipul '{ name: string; email: string; }' nu poate fi atribuit tipului 'string'.
Ce fac greșit?
Am citit aceste întrebări (Cum să definești un tip Typescript ca un dicționar de șiruri de caractere, dar cu o proprietate numerică „id”, Proprietatea nu poate fi atribuită unui index de tip șir într-o interfață), și am încercat să-mi modific codul astfel, dar tot nu funcționează:
export interface Login {
date: string;
user: {
name: string;
email: string;
};
otherFields?: Other;
}
export type LoginFormatted = {
Date: string;
UserInfo: {
name: string;
email: string;
};
} & Other;
interface Other {
[key: string]: string;
}
Răspuns #1
De fapt, cred că celelalte întrebări legate în comentarii au răspunsuri mai bune decât aceasta, dar întrebarea ta m-a făcut curios, așa că am încercat eu însumi câteva variante ca să văd cum funcționează TypeScript în aceste cazuri.
Definiție de Tip
În ceea ce privește aspectul Definiției Tipului, din câte pot vedea, totul funcționează fără probleme:
type Combine = {
Core: {
Name: string;
Colour: string;
}
} & { [key: string]: string }
// then writing
const combine: Combine = {... we'll see this...}
combine.Core.Name // is prompted and doesn't give any error
combine["attachment"] // this also doesn't give any error
Deci, în ceea ce privește tipul Combine, se pare că TypeScript adaugă corect câmpul Core la un dicționar string-string.
Crearea instanțelor
Acum problema este cum facem o instanță a acelui tip Combine, pentru că atunci TypeScript dă greș.
// this gives the same error as you reported
const combine: Combine = {
Core: {
Name: "Wheatley",
Colour: "Blue"
}
}
// while this says "hey, it must include a Core field!" ಠ_ಠ
const combine: Combine = {
attachment: "nope!"
}
Presupun că acest lucru se întâmplă pentru că atunci când definești un dicționar, verificarea string-string intră în funcțiune și nu îți permite să declari alte tipuri, în timp ce atunci când respecți corect constrângerea string-string, realizează că îi lipsește celălalt câmp Core.
Soluții și trucuri
Așa cum am spus, celelalte întrebări au răspunsuri mult mai detaliate și clare la această problemă, cum ar fi să lași dicționarul într-un subcâmp separat fără a-l amesteca cu câmpul Core sau să creezi un dicționar cu tipuri multiple în locul unuia strict string-string.
Totuși, chiar pare prost să funcționeze impecabil când te ocupi de instanța reală, dar să nu poți să creezi una corespunzător.
Așa că m-am gândit la acest mic „truc” care pare să funcționeze
const combine: Combine = {
Core: {
Name: "Wheatley",
Colour: "Blue"
}
attachment: "nope!"
} as unknown as Combine
Deci practic spargi tipizarea TS și apoi o pui la loc.
Deci, în cazul tău ar fi suficient să scrii ceva de genul:
const formatData = (data: Login): LoginFormatted => {
return {
Date: data.date,
UserInfo: {
name: data.user.name,
email: data.user.email
},
...data.otherFields
} as unknown as LoginFormatted;
};
Pentru ca totul să funcționeze.
Răspunsul #2
ajustați loggingFormatted la următoarele
export type LoginFormatted = {
[key: string]: string;
Date: string;
UserInfo: {
name: string;
email: string;
};
};
această semnătură de index va necesita Date și UserInfo în timp ce permite extinderea cu alte proprietăți.
