reactjs - Generellt sätt att konvertera alla förekomster av null till undefined i TypeScript
Jag vill skriva en funktion som konverterar alla förekomster av en egenskap hos vilket objekt som helst som är null till undefined. Många av mina objekt har nästlade objekt som egenskaper eller arrayer av värden/objekt.
Min första tanke när jag närmar mig problemet är att använda generiska typer för att försöka fånga typen av varje egenskap med en generisk typ och sedan konvertera värdet av den egenskapen från null till undefined vid behov.
Jag hoppas skriva en funktion som är tillräckligt generell för att fungera över alla olika typer och storlekar av objekt jag har i min kodbas.
Jag har inte kunnat hitta ett enkelt sätt att ha ett okänt antal generiska typer, så min nästa tanke är att jag kommer att behöva använda typen any överallt. Finns det ett sätt att komma runt detta?
Jag skulle också vilja ha lite råd om själva tillvägagångssättet/algoritmen. Min tanke är att jag förmodligen behöver rekursivt kontrollera varje egenskap för att se om den själv är ett objekt med underliggande egenskaper, och jag kommer också behöva iterera över eventuella arrayer som hittas som kan ha ett nollvärde, eller ha ett objekt som också behöver kontrolleras rekursivt.
De problem/frågor jag behöver lösa/svara på:
- Ska jag använda Generics eller Any?
- Om jag använder generiska typer, finns det ett sätt att dynamiskt tilldela nya generiska typer när en ny typ hittas?
- Har TypeScript ett enklare sätt att rekursivt parsa objekt?
Min nuvarande strategi är något i stil med:
inputObjectKeys.map(key, index) =>ha sedan en funktion som omvandlar null till undefined, ignorerar icke-objekt-typer och återkallar om det är ett objekt.
Jag antar att jag skulle vilja använda en bred först-sökning eller djup först-sökning (jag lutar åt bred först-sökning för denna särskilda uppgift). Jag antar att eftersom jag behöver besöka varje nod kan jag vara bättre med DFS helt enkelt på grund av minnesanvändningen.
Svar #1
Det accepterade svaret svarar faktiskt inte på frågan eftersom den efterfrågade på ett generiskt sätt.
Här är en som är liknande och som också kommer att kasta returtypen korrekt:
type RecursivelyReplaceNullWithUndefined<T> = T extends null
? undefined
: T extends Date
? T
: {
[K in keyof T]: T[K] extends (infer U)[]
? RecursivelyReplaceNullWithUndefined<U>[]
: RecursivelyReplaceNullWithUndefined<T[K]>;
};
export function nullsToUndefined<T>(obj: T): RecursivelyReplaceNullWithUndefined<T> {
if (obj === null) {
return undefined as any;
}
// object check based on: https://stackoverflow.com/a/51458052/6489012
if (obj.constructor.name === "Object") {
for (let key in obj) {
obj[key] = nullsToUndefined(obj[key]) as any;
}
}
return obj as any;
}
Beröm går till typsättningarna av detta geni: https://github.com/apollographql/apollo-client/issues/2412#issuecomment-755449680
Svar #2
Det accepterade svaret är inte typ-säkert.
Detta svar är nära, men hanterar inte null inuti nästlade arrayer.
Detta kommer att ersätta null med undefined i nästlade objekt och arrayer:
type RecursivelyReplaceNullWithUndefined<T> = T extends null
? undefined
: T extends (infer U)[]
? RecursivelyReplaceNullWithUndefined<U>[]
: T extends Record<string, unknown>
? { [K in keyof T]: RecursivelyReplaceNullWithUndefined<T[K]> }
: T;
export function nullsToUndefined<T>(
obj: T,
): RecursivelyReplaceNullWithUndefined<T> {
if (obj === null || obj === undefined) {
return undefined as any;
}
if ((obj as any).constructor.name === 'Object' || Array.isArray(obj)) {
for (const key in obj) {
obj[key] = nullsToUndefined(obj[key]) as any;
}
}
return obj as any;
}
