diff --git a/crates/cli-support/src/js/js2rust.rs b/crates/cli-support/src/js/js2rust.rs index db5387a5..13a531f8 100644 --- a/crates/cli-support/src/js/js2rust.rs +++ b/crates/cli-support/src/js/js2rust.rs @@ -805,16 +805,30 @@ impl<'a, 'b> Js2Rust<'a, 'b> { }; js.push_str(&invoc); js.push_str("\n}"); - let ts_args = self - .js_arguments - .iter() - .map(|s| if s.optional { - format!("{}?: {}", s.name, s.type_) + + // Determine TS parameter list + let mut omittable = true; + let mut ts_args = Vec::with_capacity(self.js_arguments.len()); + for arg in self.js_arguments.iter().rev() { + // In TypeScript, we can mark optional parameters as omittable + // using the `?` suffix, but only if they're not followed by + // non-omittable parameters. Therefore iterate the parameter list + // in reverse and stop using the `?` suffix for optional params as + // soon as a non-optional parameter is encountered. + if arg.optional { + if omittable { + ts_args.push(format!("{}?: {}", arg.name, arg.type_)); + } else { + ts_args.push(format!("{}: {} | undefined", arg.name, arg.type_)); + } } else { - format!("{}: {}", s.name, s.type_) - }) - .collect::<Vec<_>>() - .join(", "); + omittable = false; + ts_args.push(format!("{}: {}", arg.name, arg.type_)); + } + } + ts_args.reverse(); + let ts_args = ts_args.join(", "); + let mut ts = if prefix.is_empty() { format!("{}({})", self.js_name, ts_args) } else {