TypeScript如何移除对象__typename字段?Formik数据处理求助
__typename Fields from Typed Objects in TypeScript for Formik Initial Values I'm working with typed data that includes the __typename metadata field (common with GraphQL responses), and I need to use this data to set initial values for a Formik form. The issue is that sending data with __typename to my server causes syntax errors, so I defined separate types for the form fields that exclude this metadata:
type MainRecord = { id: string; fieldOne: string; related: RelatedRecord[]; __typename: string } type RelatedRecord = { id: string; fieldTwo: string; __typename: string } // Form-specific types without __typename type MainFields = { id: string; fieldOne: string; related: RelatedFields[] } type RelatedFields = { id: string; fieldTwo: string }
When I try to cast a MainRecord to MainFields (either directly or with as MainFields), the __typename fields still exist in the runtime object:
const record: MainRecord = { id: "10", fieldOne: "Foo", __typename: "Main", related: [ { id: "20", fieldTwo: "Bar", __typename: "Related" }, { id: "21", fieldTwo: "Baz", __typename: "Related" } ] } const fields: MainFields = record // Or record as MainFields console.log(fields) // Still includes __typename in both the root and related objects
I don't want to manually delete these fields one by one—what's a clean, TypeScript-native way to handle this?
Great question! The key thing to remember here is that TypeScript type assertions/casts only affect compile-time type checking, not runtime data. So even though you tell TypeScript fields is a MainFields, the actual object still has all its original properties, including __typename.
Here are a few robust, maintainable solutions to fix this:
1. Recursive Utility Function (Runtime + Type Safety)
Since your data has nested arrays, a recursive function will handle both objects and arrays to strip out __typename everywhere. We can pair this with a type helper to ensure the return type matches your form fields perfectly:
// Type helper to recursively omit __typename from all types type OmitTypename<T> = T extends { __typename: string } ? Omit<T, '__typename'> extends infer O ? { [K in keyof O]: OmitTypename<O[K]> } : never : T extends Array<infer U> ? Array<OmitTypename<U>> : T; // Runtime function to strip __typename function stripTypename<T>(obj: T): OmitTypename<T> { if (Array.isArray(obj)) { return obj.map(stripTypename) as OmitTypename<T>; } if (typeof obj === 'object' && obj !== null) { const { __typename, ...rest } = obj as { __typename?: string }; return Object.fromEntries( Object.entries(rest).map(([key, value]) => [key, stripTypename(value)]) ) as OmitTypename<T>; } return obj as OmitTypename<T>; } // Usage const fields: MainFields = stripTypename(record); console.log(fields) // No __typename fields left, and type matches MainFields exactly
This works for any nested structure, keeps your types in sync, and handles both objects and arrays automatically—no manual field deletion required.
2. Destructuring + Mapping (For Simple Structures)
If your data structure isn't too deeply nested, you can use object destructuring to exclude __typename at the root, and map for the related array:
const { __typename, ...rootFields } = record; const fields: MainFields = { ...rootFields, related: record.related.map(({ __typename, ...relatedFields }) => relatedFields) };
This is more explicit for small, flat structures, but becomes cumbersome if you have multiple levels of nested objects/arrays.
Why Type Casting Alone Doesn't Work
To reiterate: TypeScript is a static type system—it doesn't modify your actual JavaScript at runtime. When you write record as MainFields, you're just telling TypeScript "treat this object as if it's a MainFields", but the underlying object still retains all its original properties. You need a runtime solution to actually remove the __typename fields before sending data to the server.
内容的提问来源于stack exchange,提问作者aarona

