mirror of
https://github.com/xazukx/ts-rs.git
synced 2026-08-23 12:58:33 +00:00
fix regression: #[ts(optional)] incompatible with #[ts(type = ...)] (#416)
This commit is contained in:
@@ -106,13 +106,6 @@ impl Attr for FieldAttr {
|
||||
"`type` is not compatible with `flatten`"
|
||||
);
|
||||
}
|
||||
|
||||
if let Optional::Optional { .. } = self.optional {
|
||||
syn_err_spanned!(
|
||||
field;
|
||||
"`type` is not compatible with `optional`"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if self.flatten {
|
||||
|
||||
@@ -64,10 +64,10 @@ pub fn apply(
|
||||
crate_rename: &Path,
|
||||
for_struct: Optional,
|
||||
field_ty: &Type,
|
||||
field_attr: &FieldAttr,
|
||||
attr: &FieldAttr,
|
||||
span: Span,
|
||||
) -> (Expr, Type) {
|
||||
match (for_struct, field_attr.optional) {
|
||||
match (for_struct, attr.optional) {
|
||||
// explicit `#[ts(optional = false)]` on field, or inherited from struct.
|
||||
(Optional::NotOptional, Optional::Inherit) | (_, Optional::NotOptional) => {
|
||||
(parse_quote!(false), field_ty.clone())
|
||||
@@ -89,7 +89,7 @@ pub fn apply(
|
||||
// Inherited `#[ts(optional)]` from the struct.
|
||||
// Acts like `#[ts(optional)]` on a field, but does not error on non-`Option` fields.
|
||||
// Instead, it is a no-op.
|
||||
(Optional::Optional { nullable }, Optional::Inherit) => (
|
||||
(Optional::Optional { nullable }, Optional::Inherit) if attr.type_override.is_none() => (
|
||||
parse_quote! {
|
||||
<#field_ty as #crate_rename::TS>::IS_OPTION
|
||||
},
|
||||
@@ -97,10 +97,11 @@ pub fn apply(
|
||||
.then(|| field_ty.clone())
|
||||
.unwrap_or_else(|| unwrap_option(crate_rename, field_ty)),
|
||||
),
|
||||
// field may be omitted during serialization and has a default value, so the field can be
|
||||
// treated as `#[ts(optional = nullable)]`.
|
||||
(Optional::Inherit, Optional::Inherit) => {
|
||||
let is_optional = field_attr.maybe_omitted && field_attr.has_default;
|
||||
// no applicable `#[ts(optional)]` attributes
|
||||
_ => {
|
||||
// field may be omitted during serialization and has a default value, so the field can be
|
||||
// treated as `#[ts(optional = nullable)]`.
|
||||
let is_optional = attr.maybe_omitted && attr.has_default;
|
||||
(parse_quote!(#is_optional), field_ty.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,28 +102,6 @@ fn format_field(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(ref type_override) = field_attr.type_override {
|
||||
let field_name = to_ts_ident(field.ident.as_ref().unwrap());
|
||||
let name = match (field_attr.rename.as_ref(), rename_all) {
|
||||
(Some(rn), _) => rn.to_owned(),
|
||||
(None, Some(rn)) => rn.apply(&field_name),
|
||||
(None, None) => field_name,
|
||||
};
|
||||
let valid_name = raw_name_to_ts_field(name);
|
||||
|
||||
// Start every doc string with a newline, because when other characters are in front, it is not "understood" by VSCode
|
||||
let docs = match &*field_attr.docs {
|
||||
&[] => quote!(""),
|
||||
docs => quote!(format!("\n{}", #crate_rename::format_docs(&[#(#docs),*]))),
|
||||
};
|
||||
|
||||
formatted_fields.push(quote! {
|
||||
format!("{}{}: {},", #docs, #valid_name, #type_override)
|
||||
});
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let ty = field_attr.type_as(&field.ty);
|
||||
|
||||
let (is_optional, ty) = crate::optional::apply(
|
||||
@@ -141,13 +119,18 @@ fn format_field(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let formatted_ty = if field_attr.inline {
|
||||
dependencies.append_from(&ty);
|
||||
quote!(<#ty as #crate_rename::TS>::inline())
|
||||
} else {
|
||||
dependencies.push(&ty);
|
||||
quote!(<#ty as #crate_rename::TS>::name())
|
||||
};
|
||||
let formatted_ty = field_attr
|
||||
.type_override
|
||||
.map(|t| quote!(#t))
|
||||
.unwrap_or_else(|| {
|
||||
if field_attr.inline {
|
||||
dependencies.append_from(&ty);
|
||||
quote!(<#ty as #crate_rename::TS>::inline())
|
||||
} else {
|
||||
dependencies.push(&ty);
|
||||
quote!(<#ty as #crate_rename::TS>::name())
|
||||
}
|
||||
});
|
||||
|
||||
let field_name = to_ts_ident(field.ident.as_ref().unwrap());
|
||||
let name = match (field_attr.rename, rename_all) {
|
||||
|
||||
@@ -56,11 +56,6 @@ fn format_field(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(ref type_override) = field_attr.type_override {
|
||||
formatted_fields.push(quote!(#type_override.to_owned()));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let ty = field_attr.type_as(&field.ty);
|
||||
let (is_optional, ty) = crate::optional::apply(
|
||||
crate_rename,
|
||||
@@ -70,13 +65,18 @@ fn format_field(
|
||||
field.span(),
|
||||
);
|
||||
|
||||
let formatted_ty = if field_attr.inline {
|
||||
dependencies.append_from(&ty);
|
||||
quote!(<#ty as #crate_rename::TS>::inline())
|
||||
} else {
|
||||
dependencies.push(&ty);
|
||||
quote!(<#ty as #crate_rename::TS>::name())
|
||||
};
|
||||
let formatted_ty = field_attr
|
||||
.type_override
|
||||
.map(|t| quote!(#t.to_owned()))
|
||||
.unwrap_or_else(|| {
|
||||
if field_attr.inline {
|
||||
dependencies.append_from(&ty);
|
||||
quote!(<#ty as #crate_rename::TS>::inline())
|
||||
} else {
|
||||
dependencies.push(&ty);
|
||||
quote!(<#ty as #crate_rename::TS>::name())
|
||||
}
|
||||
});
|
||||
|
||||
formatted_fields.push(quote! {
|
||||
if #is_optional {
|
||||
|
||||
26
ts-rs/tests/integration/issue_415.rs
Normal file
26
ts-rs/tests/integration/issue_415.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
#![cfg(feature = "serde-compat")]
|
||||
|
||||
use ts_rs::TS;
|
||||
|
||||
struct Foreign;
|
||||
|
||||
#[derive(TS)]
|
||||
#[ts(export, export_to = "issue_415/")]
|
||||
struct Issue415 {
|
||||
#[ts(optional, type = "Date")]
|
||||
a: Option<Foreign>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_415() {
|
||||
assert_eq!(Issue415::decl(), "type Issue415 = { a?: Date, };");
|
||||
}
|
||||
|
||||
#[derive(TS)]
|
||||
#[ts(export, export_to = "issue_415/")]
|
||||
struct InTuple(i32, #[ts(optional, type = "Date")] Option<Foreign>);
|
||||
|
||||
#[test]
|
||||
fn in_tuple() {
|
||||
assert_eq!(InTuple::decl(), "type InTuple = [number, (Date)?];");
|
||||
}
|
||||
@@ -31,6 +31,7 @@ mod issue_308;
|
||||
mod issue_317;
|
||||
mod issue_338;
|
||||
mod issue_397;
|
||||
mod issue_415;
|
||||
mod issue_70;
|
||||
mod issue_80;
|
||||
mod leading_colon;
|
||||
|
||||
Reference in New Issue
Block a user