Typescript-fel vid konvertering av en typ till en annan
Jag har en funktion som formaterar viss data från en typ till en annan. Den ändrar i princip vissa format och förenklar vissa fält.
Det här är min kod:
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" }
});
Och mina typer:
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 };
HÄR är den fungerande koden
Jag får ett TypeScript-fel i formatData:
Typen '{ Date: string; UserInfo: { name: string; email: string; }; }' kan inte tilldelas typen 'LoginFormatted'. Typen '{ Date: string; UserInfo: { name: string; email: string; }; }' kan inte tilldelas typen '{ [key: string]: string; }'. Egenskapen 'UserInfo' är inkompatibel med indexsignaturen. Typen '{ name: string; email: string; }' kan inte tilldelas typen 'string'.
Vad gör jag för fel?
Jag läste dessa frågor (Hur man definierar en Typescript-typ som en ordbok av strängar men med en numerisk "id"-egenskap, Egenskapen kan inte tilldelas till strängindex i gränssnittet), och jag försökte ändra min kod så här men det fungerar fortfarande inte:
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;
}
Svar #1
Jag tycker faktiskt att de andra frågorna som länkats i kommentarerna har bättre svar än detta, men din fråga gjorde mig nyfiken så jag gjorde ett par försök själv för att se hur TypeScript fungerar i dessa fall.
Typdefinition
När det gäller typdefinitionen, såvitt jag kan se, fungerar allt smidigt:
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
Så när det gäller typen Combine verkar TypeScript korrekt lägga till fältet Core till en sträng-sträng-ordbok.
Skapa instanser
Nu är problemet hur vi skapar en instans av den typen Combine, eftersom det är då TypeScript gör fel.
// 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!"
}
Jag antar att det beror på att när du definierar en ordbok så aktiveras sträng-sträng-kontrollen och tillåter dig inte att deklarera andra typer, medan när du korrekt följer sträng-sträng-begränsningen inser den att det saknas det andra Core-fältet.
Lösningar & Hacks
Nu som jag sa har de andra frågorna ganska mer djupgående och tydliga svar på detta problem, som att lämna ordboken till ett separat delområde utan att blanda det med Core-fältet eller göra en ordbok med flera typer istället för en strikt sträng-sträng.
Ändå känns det verkligen dumt att det fungerar perfekt när man hanterar det faktiska exemplet, men att man inte kan skapa ett på rätt sätt.
Så jag kom på denna lilla "hack" som verkar fungera
const combine: Combine = {
Core: {
Name: "Wheatley",
Colour: "Blue"
}
attachment: "nope!"
} as unknown as Combine
Så i princip bryter du TS-typning och sätter sedan ihop det igen.
Så i ditt fall skulle det räcka att skriva något som:
const formatData = (data: Login): LoginFormatted => {
return {
Date: data.date,
UserInfo: {
name: data.user.name,
email: data.user.email
},
...data.otherFields
} as unknown as LoginFormatted;
};
Att få allt att fungera.
Svar #2
anpassa loggingFormatted till följande
export type LoginFormatted = {
[key: string]: string;
Date: string;
UserInfo: {
name: string;
email: string;
};
};
denna indexsignatur kommer att kräva Date och UserInfo samtidigt som den tillåter utvidgning med andra egenskaper.
