Repository: 1Password/typeshare (rust)

Issue:
Macro params to override generated type
Thanks for the tool!
Currently this struct
```rust
#[typeshare]
pub struct OrderItem {
  #[ts(type = "any | null")]
  pub meta: Option<Value>,
}
```
will generate this ts type
```typescript
export interface OrderItem {
	meta?: Value;
}
```
where `Value` is `serde_json::Value`
I wonder if it's a good idea to support something like this
```rust
#[typeshare]
pub struct OrderItem {
  #[typeshare(type = "any | null")]
  pub meta: Option<Value>,
}
```

Pull request description:
Parameter to override a field type on a per-language basis
Resolves #22.

There is now a field decorator that can override the type of the field in the generated language(s) of your choice. This override takes precedent over everything else, including type mapping.

Patch:
diff --git a/core/src/language/go.rs b/core/src/language/go.rs
index 9cd3a9d..2ecf055 100644
--- a/core/src/language/go.rs
+++ b/core/src/language/go.rs
@@ -1,5 +1,6 @@
 use std::io::Write;
 
+use crate::language::SupportedLanguage;
 use crate::parser::ParsedData;
 use crate::rename::RenameExt;
 use crate::rust_types::{RustItem, RustTypeFormatError, SpecialRustType};
@@ -401,9 +402,14 @@ func ({short_name} {full_name}) MarshalJSON() ([]byte, error) {{
         }
 
         write_comments(w, 1, &field.comments)?;
-        let type_name = self
-            .format_type(&field.ty, generic_types)
-            .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
+
+        let type_name = match field.type_override(SupportedLanguage::Go) {
+            Some(type_override) => type_override.to_owned(),
+            None => self
+                .format_type(&field.ty, generic_types)
+                .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?,
+        };
+
         let go_type = self.acronyms_to_uppercase(&type_name);
         let is_optional = field.ty.is_optional() || field.has_default;
         let formatted_renamed_id = format!("{:?}", &field.id.renamed);
diff --git a/core/src/language/kotlin.rs b/core/src/language/kotlin.rs
index fe9703d..ac38e6a 100644
--- a/core/src/language/kotlin.rs
+++ b/core/src/language/kotlin.rs
@@ -1,4 +1,5 @@
 use super::Language;
+use crate::language::SupportedLanguage;
 use crate::rust_types::{RustTypeFormatError, SpecialRustType};
 use crate::{
     parser::remove_dash_from_identifier,
@@ -313,9 +314,13 @@ impl Kotlin {
         if requires_serial_name {
             writeln!(w, "\t@SerialName({:?})", &f.id.renamed)?;
         }
-        let ty = self
-            .format_type(&f.ty, generic_types)
-            .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
+        let ty = match f.type_override(SupportedLanguage::Kotlin) {
+            Some(type_override) => type_override.to_owned(),
+            None => self
+                .format_type(&f.ty, generic_types)
+                .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?,
+        };
+
         write!(
             w,
             "\tval {}: {}{}",
diff --git a/core/src/language/scala.rs b/core/src/language/scala.rs
index be7ce99..9ce0d52 100644
--- a/core/src/language/scala.rs
+++ b/core/src/language/scala.rs
@@ -1,4 +1,5 @@
 use super::Language;
+use crate::language::SupportedLanguage;
 use crate::parser::ParsedData;
 use crate::rust_types::{RustType, RustTypeFormatError, SpecialRustType};
 use crate::{
@@ -342,9 +343,14 @@ impl Scala {
         generic_types: &[String],
     ) -> std::io::Result<()> {
         self.write_comments(w, 1, &f.comments)?;
-        let ty = self
-            .format_type(&f.ty, generic_types)
-            .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
+
+        let ty = match f.type_override(SupportedLanguage::Scala) {
+            Some(type_override) => type_override.to_owned(),
+            None => self
+                .format_type(&f.ty, generic_types)
+                .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?,
+        };
+
         write!(
             w,
             "\t{}: {}{}",
diff --git a/core/src/language/swift.rs b/core/src/language/swift.rs
index fdf5282..a1d86bc 100644
--- a/core/src/language/swift.rs
+++ b/core/src/language/swift.rs
@@ -9,6 +9,7 @@ use itertools::Itertools;
 use joinery::JoinableIterator;
 use lazy_format::lazy_format;
 use std::collections::BTreeSet;
+use std::io;
 use std::{
     collections::HashMap,
     io::Write,
@@ -205,7 +206,7 @@ impl Language for Swift {
         })
     }
 
-    fn begin_file(&mut self, w: &mut dyn Write) -> std::io::Result<()> {
+    fn begin_file(&mut self, w: &mut dyn Write) -> io::Result<()> {
         if !self.no_version_header {
             writeln!(w, "/*")?;
             writeln!(w, " Generated by typeshare {}", env!("CARGO_PKG_VERSION"))?;
@@ -216,7 +217,7 @@ impl Language for Swift {
         Ok(())
     }
 
-    fn end_file(&mut self, w: &mut dyn Write) -> std::io::Result<()> {
+    fn end_file(&mut self, w: &mut dyn Write) -> io::Result<()> {
         if self.should_emit_codable_void.load(Ordering::SeqCst) {
             writeln!(w)?;
             writeln!(
@@ -237,7 +238,7 @@ impl Language for Swift {
         Ok(())
     }
 
-    fn write_type_alias(&mut self, w: &mut dyn Write, ty: &RustTypeAlias) -> std::io::Result<()> {
+    fn write_type_alias(&mut self, w: &mut dyn Write, ty: &RustTypeAlias) -> io::Result<()> {
         writeln!(w)?;
         self.write_comments(w, 0, &ty.comments)?;
 
@@ -258,7 +259,7 @@ impl Language for Swift {
         Ok(())
     }
 
-    fn write_struct(&mut self, w: &mut dyn Write, rs: &RustStruct) -> std::io::Result<()> {
+    fn write_struct(&mut self, w: &mut dyn Write, rs: &RustStruct) -> io::Result<()> {
         let mut coding_keys = vec![];
         let mut should_write_coding_keys = false;
 
@@ -329,9 +330,13 @@ impl Language for Swift {
                 )));
             }
 
-            let case_type = self
-                .format_type(&f.ty, rs.generic_types.as_slice())
-                .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
+            let case_type: String = match f.type_override(SupportedLanguage::Swift) {
+                Some(type_override) => type_override.to_owned(),
+                None => self
+                    .format_type(&f.ty, rs.generic_types.as_slice())
+                    .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
+            };
+
             writeln!(
                 w,
                 "\tpublic let {}: {}{}",
@@ -360,9 +365,13 @@ impl Language for Swift {
 
         let mut init_params: Vec<String> = Vec::new();
         for f in &rs.fields {
-            let swift_ty = self
-                .format_type(&f.ty, rs.generic_types.as_slice())
-                .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
+            let swift_ty = match f.type_override(SupportedLanguage::Swift) {
+                Some(type_override) => type_override.to_owned(),
+                None => self
+                    .format_type(&f.ty, rs.generic_types.as_slice())
+                    .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
+            };
+
             init_params.push(format!(
                 "{}: {}{}",
                 remove_dash_from_identifier(&f.id.renamed),
@@ -391,7 +400,7 @@ impl Language for Swift {
         Ok(())
     }
 
-    fn write_enum(&mut self, w: &mut dyn Write, e: &RustEnum) -> std::io::Result<()> {
+    fn write_enum(&mut self, w: &mut dyn Write, e: &RustEnum) -> io::Result<()> {
         /// Determines the decorators needed for an enum given an array of decorators
         /// that should always be present
         fn determine_decorators(always_present: &[String], e: &RustEnum) -> Vec<String> {
@@ -528,7 +537,7 @@ impl Swift {
         w: &mut dyn Write,
         e: &RustEnum,
         make_anonymous_struct_name: impl Fn(&str) -> String,
-    ) -> std::io::Result<CodingKeysInfo> {
+    ) -> io::Result<CodingKeysInfo> {
         let mut decoding_cases = Vec::new();
         let mut encoding_cases = Vec::new();
         let mut coding_keys = Vec::new();
@@ -613,7 +622,7 @@ impl Swift {
                             let content_optional = ty.is_optional();
                             let case_type = self
                                 .format_type(ty, e.shared().generic_types.as_slice())
-                                .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
+                                .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
                             write!(w, "({})", swift_keyword_aware_rename(&case_type))?;
 
                             if content_optional {
@@ -719,12 +728,7 @@ impl Swift {
         })
     }
 
-    fn write_comment(
-        &mut self,
-        w: &mut dyn Write,
-        indent: usize,
-        comment: &str,
-    ) -> std::io::Result<()> {
+    fn write_comment(&mut self, w: &mut dyn Write, indent: usize, comment: &str) -> io::Result<()> {
         writeln!(w, "{}/// {}", "\t".repeat(indent), comment.trim_end())?;
         Ok(())
     }
@@ -734,7 +738,7 @@ impl Swift {
         w: &mut dyn Write,
         indent: usize,
         comments: &[String],
-    ) -> std::io::Result<()> {
+    ) -> io::Result<()> {
         comments
             .iter()
             .try_for_each(|c| self.write_comment(w, indent, c))
diff --git a/core/src/language/typescript.rs b/core/src/language/typescript.rs
index ff624c1..cffea1f 100644
--- a/core/src/language/typescript.rs
+++ b/core/src/language/typescript.rs
@@ -5,6 +5,7 @@ use crate::{
     language::{Language, SupportedLanguage},
     rust_types::{RustEnum, RustEnumVariant, RustField, RustStruct, RustTypeAlias},
 };
+use std::io;
 use std::{collections::HashMap, io::Write};
 
 /// All information needed to generate Typescript type-code
@@ -74,7 +75,7 @@ impl Language for TypeScript {
         }
     }
 
-    fn begin_file(&mut self, w: &mut dyn Write) -> std::io::Result<()> {
+    fn begin_file(&mut self, w: &mut dyn Write) -> io::Result<()> {
         if !self.no_version_header {
             writeln!(w, "/*")?;
             writeln!(w, " Generated by typeshare {}", env!("CARGO_PKG_VERSION"))?;
@@ -84,12 +85,12 @@ impl Language for TypeScript {
         Ok(())
     }
 
-    fn write_type_alias(&mut self, w: &mut dyn Write, ty: &RustTypeAlias) -> std::io::Result<()> {
+    fn write_type_alias(&mut self, w: &mut dyn Write, ty: &RustTypeAlias) -> io::Result<()> {
         self.write_comments(w, 0, &ty.comments)?;
 
         let r#type = self
             .format_type(&ty.r#type, ty.generic_types.as_slice())
-            .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
+            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
 
         writeln!(
             w,
@@ -108,7 +109,7 @@ impl Language for TypeScript {
         Ok(())
     }
 
-    fn write_struct(&mut self, w: &mut dyn Write, rs: &RustStruct) -> std::io::Result<()> {
+    fn write_struct(&mut self, w: &mut dyn Write, rs: &RustStruct) -> io::Result<()> {
         self.write_comments(w, 0, &rs.comments)?;
         writeln!(
             w,
@@ -126,7 +127,7 @@ impl Language for TypeScript {
         writeln!(w, "}}\n")
     }
 
-    fn write_enum(&mut self, w: &mut dyn Write, e: &RustEnum) -> std::io::Result<()> {
+    fn write_enum(&mut self, w: &mut dyn Write, e: &RustEnum) -> io::Result<()> {
         self.write_comments(w, 0, &e.shared().comments)?;
 
         let generic_parameters = (!e.shared().generic_types.is_empty())
@@ -163,7 +164,7 @@ impl Language for TypeScript {
 }
 
 impl TypeScript {
-    fn write_enum_variants(&mut self, w: &mut dyn Write, e: &RustEnum) -> std::io::Result<()> {
+    fn write_enum_variants(&mut self, w: &mut dyn Write, e: &RustEnum) -> io::Result<()> {
         match e {
             // Write all the unit variants out (there can only be unit variants in
             // this case)
@@ -194,7 +195,7 @@ impl TypeScript {
                     RustEnumVariant::Tuple { ty, shared } => {
                         let r#type = self
                             .format_type(ty, e.shared().generic_types.as_slice())
-                            .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
+                            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
                         write!(
                             w,
                             "\t| {{ {}: {:?}, {}{}: {} }}",
@@ -229,11 +230,15 @@ impl TypeScript {
         w: &mut dyn Write,
         field: &RustField,
         generic_types: &[String],
-    ) -> std::io::Result<()> {
+    ) -> io::Result<()> {
         self.write_comments(w, 1, &field.comments)?;
-        let ts_ty = self
-            .format_type(&field.ty, generic_types)
-            .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
+        let ts_ty: String = match field.type_override(SupportedLanguage::TypeScript) {
+            Some(type_override) => type_override.to_owned(),
+            None => self
+                .format_type(&field.ty, generic_types)
+                .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
+        };
+
         let optional = field.ty.is_optional() || field.has_default;
         let double_optional = field.ty.is_double_optional();
         let is_readonly = field
@@ -259,7 +264,7 @@ impl TypeScript {
         w: &mut dyn Write,
         indent: usize,
         comments: &[String],
-    ) -> std::io::Result<()> {
+    ) -> io::Result<()> {
         // Only attempt to write a comment if there are some, otherwise we're Ok()
         if !comments.is_empty() {
             let comment: String = {
diff --git a/core/src/rust_types.rs b/core/src/rust_types.rs
index f72c10f..e14d13c 100644
--- a/core/src/rust_types.rs
+++ b/core/src/rust_types.rs
@@ -346,6 +346,19 @@ impl RustType {
     }
 }
 
+impl RustField {
+    /// Returns an type override, if it exists, on this field for a given language.
+    pub fn type_override(&self, language: SupportedLanguage) -> Option<&str> {
+        self.decorators
+            .get(&language)?
+            .iter()
+            .find_map(|fd| match fd {
+                FieldDecorator::NameValue(name, ty) if name == "type" => Some(ty.as_str()),
+                _ => None,
+            })
+    }
+}
+
 #[derive(Debug, Error)]
 #[allow(missing_docs)]
 pub enum RustTypeFormatError {


Test patch:
diff --git a/core/data/tests/can_override_types/input.rs b/core/data/tests/can_override_types/input.rs
new file mode 100644
index 0000000..994cc9a
--- /dev/null
+++ b/core/data/tests/can_override_types/input.rs
@@ -0,0 +1,29 @@
+#[typeshare]
+#[serde(rename_all = "camelCase")]
+struct OverrideStruct {
+    // These annotations are intentionally inconsistent across languages
+    #[typeshare(
+        swift(type = "Int"),
+        typescript(readonly, type = "any | undefined"),
+        kotlin(type = "Int"), go(type = "uint"),
+        scala(type = "Short")
+    )]
+    field_to_override: String,
+}
+
+#[typeshare]
+#[serde(tag = "type", content = "content")]
+enum OverrideEnum {
+    UnitVariant,
+    TupleVariant(String),
+    #[serde(rename_all = "camelCase")]
+    AnonymousStructVariant {
+        #[typeshare(
+            swift(type = "Int"),
+            typescript(readonly, type = "any | undefined"),
+            kotlin(type = "Int"), go(type = "uint"),
+            scala(type = "Short")
+        )]
+        field_to_override: String
+    }
+}
\ No newline at end of file
diff --git a/core/data/tests/can_override_types/output.go b/core/data/tests/can_override_types/output.go
new file mode 100644
index 0000000..b8038c6
--- /dev/null
+++ b/core/data/tests/can_override_types/output.go
@@ -0,0 +1,87 @@
+package proto
+
+import "encoding/json"
+
+type OverrideStruct struct {
+	FieldToOverride uint `json:"fieldToOverride"`
+}
+// Generated type representing the anonymous struct variant `AnonymousStructVariant` of the `OverrideEnum` Rust enum
+type OverrideEnumAnonymousStructVariantInner struct {
+	FieldToOverride uint `json:"fieldToOverride"`
+}
+type OverrideEnumTypes string
+const (
+	OverrideEnumTypeVariantUnitVariant OverrideEnumTypes = "UnitVariant"
+	OverrideEnumTypeVariantTupleVariant OverrideEnumTypes = "TupleVariant"
+	OverrideEnumTypeVariantAnonymousStructVariant OverrideEnumTypes = "AnonymousStructVariant"
+)
+type OverrideEnum struct{ 
+	Type OverrideEnumTypes `json:"type"`
+	content interface{}
+}
+
+func (o *OverrideEnum) UnmarshalJSON(data []byte) error {
+	var enum struct {
+		Tag    OverrideEnumTypes   `json:"type"`
+		Content json.RawMessage `json:"content"`
+	}
+	if err := json.Unmarshal(data, &enum); err != nil {
+		return err
+	}
+
+	o.Type = enum.Tag
+	switch o.Type {
+	case OverrideEnumTypeVariantUnitVariant:
+		return nil
+	case OverrideEnumTypeVariantTupleVariant:
+		var res string
+		o.content = &res
+	case OverrideEnumTypeVariantAnonymousStructVariant:
+		var res OverrideEnumAnonymousStructVariantInner
+		o.content = &res
+
+	}
+	if err := json.Unmarshal(enum.Content, &o.content); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (o OverrideEnum) MarshalJSON() ([]byte, error) {
+    var enum struct {
+		Tag    OverrideEnumTypes   `json:"type"`
+		Content interface{} `json:"content,omitempty"`
+    }
+    enum.Tag = o.Type
+    enum.Content = o.content
+    return json.Marshal(enum)
+}
+
+func (o OverrideEnum) TupleVariant() string {
+	res, _ := o.content.(*string)
+	return *res
+}
+func (o OverrideEnum) AnonymousStructVariant() *OverrideEnumAnonymousStructVariantInner {
+	res, _ := o.content.(*OverrideEnumAnonymousStructVariantInner)
+	return res
+}
+
+func NewOverrideEnumTypeVariantUnitVariant() OverrideEnum {
+    return OverrideEnum{
+        Type: OverrideEnumTypeVariantUnitVariant,
+    }
+}
+func NewOverrideEnumTypeVariantTupleVariant(content string) OverrideEnum {
+    return OverrideEnum{
+        Type: OverrideEnumTypeVariantTupleVariant,
+        content: &content,
+    }
+}
+func NewOverrideEnumTypeVariantAnonymousStructVariant(content *OverrideEnumAnonymousStructVariantInner) OverrideEnum {
+    return OverrideEnum{
+        Type: OverrideEnumTypeVariantAnonymousStructVariant,
+        content: content,
+    }
+}
+
diff --git a/core/data/tests/can_override_types/output.kt b/core/data/tests/can_override_types/output.kt
new file mode 100644
index 0000000..5413f77
--- /dev/null
+++ b/core/data/tests/can_override_types/output.kt
@@ -0,0 +1,31 @@
+@file:NoLiveLiterals
+
+package com.agilebits.onepassword
+
+import androidx.compose.runtime.NoLiveLiterals
+import kotlinx.serialization.*
+
+@Serializable
+data class OverrideStruct (
+	val fieldToOverride: Int
+)
+
+/// Generated type representing the anonymous struct variant `AnonymousStructVariant` of the `OverrideEnum` Rust enum
+@Serializable
+data class OverrideEnumAnonymousStructVariantInner (
+	val fieldToOverride: Int
+)
+
+@Serializable
+sealed class OverrideEnum {
+	@Serializable
+	@SerialName("UnitVariant")
+	object UnitVariant: OverrideEnum()
+	@Serializable
+	@SerialName("TupleVariant")
+	data class TupleVariant(val content: String): OverrideEnum()
+	@Serializable
+	@SerialName("AnonymousStructVariant")
+	data class AnonymousStructVariant(val content: OverrideEnumAnonymousStructVariantInner): OverrideEnum()
+}
+
diff --git a/core/data/tests/can_override_types/output.scala b/core/data/tests/can_override_types/output.scala
new file mode 100644
index 0000000..db22948
--- /dev/null
+++ b/core/data/tests/can_override_types/output.scala
@@ -0,0 +1,29 @@
+package com.agilebits
+
+package onepassword {
+
+case class OverrideStruct (
+	fieldToOverride: Short
+)
+
+// Generated type representing the anonymous struct variant `AnonymousStructVariant` of the `OverrideEnum` Rust enum
+case class OverrideEnumAnonymousStructVariantInner (
+	fieldToOverride: Short
+)
+
+sealed trait OverrideEnum {
+	def serialName: String
+}
+object OverrideEnum {
+	case object UnitVariant extends OverrideEnum {
+		val serialName: String = "UnitVariant"
+	}
+	case class TupleVariant(content: String) extends OverrideEnum {
+		val serialName: String = "TupleVariant"
+	}
+	case class AnonymousStructVariant(content: OverrideEnumAnonymousStructVariantInner) extends OverrideEnum {
+		val serialName: String = "AnonymousStructVariant"
+	}
+}
+
+}
diff --git a/core/data/tests/can_override_types/output.swift b/core/data/tests/can_override_types/output.swift
new file mode 100644
index 0000000..f64abc6
--- /dev/null
+++ b/core/data/tests/can_override_types/output.swift
@@ -0,0 +1,70 @@
+import Foundation
+
+public struct OverrideStruct: Codable {
+	public let fieldToOverride: Int
+
+	public init(fieldToOverride: Int) {
+		self.fieldToOverride = fieldToOverride
+	}
+}
+
+
+/// Generated type representing the anonymous struct variant `AnonymousStructVariant` of the `OverrideEnum` Rust enum
+public struct OverrideEnumAnonymousStructVariantInner: Codable {
+	public let fieldToOverride: Int
+
+	public init(fieldToOverride: Int) {
+		self.fieldToOverride = fieldToOverride
+	}
+}
+public enum OverrideEnum: Codable {
+	case unitVariant
+	case tupleVariant(String)
+	case anonymousStructVariant(OverrideEnumAnonymousStructVariantInner)
+
+	enum CodingKeys: String, CodingKey, Codable {
+		case unitVariant = "UnitVariant",
+			tupleVariant = "TupleVariant",
+			anonymousStructVariant = "AnonymousStructVariant"
+	}
+
+	private enum ContainerCodingKeys: String, CodingKey {
+		case type, content
+	}
+
+	public init(from decoder: Decoder) throws {
+		let container = try decoder.container(keyedBy: ContainerCodingKeys.self)
+		if let type = try? container.decode(CodingKeys.self, forKey: .type) {
+			switch type {
+			case .unitVariant:
+				self = .unitVariant
+				return
+			case .tupleVariant:
+				if let content = try? container.decode(String.self, forKey: .content) {
+					self = .tupleVariant(content)
+					return
+				}
+			case .anonymousStructVariant:
+				if let content = try? container.decode(OverrideEnumAnonymousStructVariantInner.self, forKey: .content) {
+					self = .anonymousStructVariant(content)
+					return
+				}
+			}
+		}
+		throw DecodingError.typeMismatch(OverrideEnum.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for OverrideEnum"))
+	}
+
+	public func encode(to encoder: Encoder) throws {
+		var container = encoder.container(keyedBy: ContainerCodingKeys.self)
+		switch self {
+		case .unitVariant:
+			try container.encode(CodingKeys.unitVariant, forKey: .type)
+		case .tupleVariant(let content):
+			try container.encode(CodingKeys.tupleVariant, forKey: .type)
+			try container.encode(content, forKey: .content)
+		case .anonymousStructVariant(let content):
+			try container.encode(CodingKeys.anonymousStructVariant, forKey: .type)
+			try container.encode(content, forKey: .content)
+		}
+	}
+}
diff --git a/core/data/tests/can_override_types/output.ts b/core/data/tests/can_override_types/output.ts
new file mode 100644
index 0000000..790db2f
--- /dev/null
+++ b/core/data/tests/can_override_types/output.ts
@@ -0,0 +1,11 @@
+export interface OverrideStruct {
+	readonly fieldToOverride: any | undefined;
+}
+
+export type OverrideEnum = 
+	| { type: "UnitVariant", content?: undefined }
+	| { type: "TupleVariant", content: string }
+	| { type: "AnonymousStructVariant", content: {
+	readonly fieldToOverride: any | undefined;
+}};
+
diff --git a/core/tests/snapshot_tests.rs b/core/tests/snapshot_tests.rs
index beb80d6..b8e1e06 100644
--- a/core/tests/snapshot_tests.rs
+++ b/core/tests/snapshot_tests.rs
@@ -441,6 +441,7 @@ tests! {
         typescript,
         go
     ];
+    can_override_types: [swift, kotlin, scala, typescript, go];
 
     /// Structs
     can_generate_simple_struct_with_a_comment: [kotlin, swift, typescript, scala,  go];