nitro icon indicating copy to clipboard operation
nitro copied to clipboard

iOS: Union with literal numbers will fail on build

Open shovel-kun opened this issue 7 months ago • 5 comments

What's happening?

Consider the following type:

type ColumnCount = 'auto' | '1' | '2'

Nitro generates the following Swift file:

///
/// ColumnCount.swift
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © 2025 Marc Rousavy @ Margelo
///

/**
 * Represents the JS union `ColumnCount`, backed by a C++ enum.
 */
public typealias ColumnCount = margelo.nitro.nitroreadium.ColumnCount

public extension ColumnCount {
  /**
   * Get a ColumnCount for the given String value, or
   * return `nil` if the given value was invalid/unknown.
   */
  init?(fromString string: String) {
    switch string {
      case "auto":
        self = .auto
      case "1":
        self = .1
      case "2":
        self = .2
      default:
        return nil
    }
  }

  /**
   * Get the String value this ColumnCount represents.
   */
  var stringValue: String {
    switch self {
      case .auto:
        return "auto"
      case .1:
        return "1"
      case .2:
        return "2"
    }
  }
}

Reproduceable Code

type ColumnCount = 'auto' | '1' | '2'

Relevant log output

This will cause the following error on build.

# ERROR

error '.1' is not a valid floating point literal; it must be written '0.1'
error '.2' is not a valid floating point literal; it must be written '0.2'
error cannot assign value of type 'Double' to type 'margelo.nitro.nitroreadium.ColumnCount'
error expression pattern of type 'Double' cannot match values of type 'margelo.nitro.nitroreadium.ColumnCount'

Device

iPhone 16 Emulator

Nitro Modules Version

0.25.2

Nitrogen Version

0.25.2

Can you reproduce this issue in the Nitro Example app here?

I didn't try (⚠️ your issue might get ignored & closed if you don't try this)

Additional information

shovel-kun avatar May 17 '25 14:05 shovel-kun

What? How does it go from one/two to 1/2?

mrousavy avatar May 17 '25 21:05 mrousavy

Sorry, I forgot to change from 'two' back to '2' after my fix... 😅

shovel-kun avatar May 18 '25 05:05 shovel-kun

Ah okay that makes sense. Well I guess this is a weird edge case, not sure if I even want to support that.

mrousavy avatar May 25 '25 09:05 mrousavy

If you're not willing to support that, then we could throw a codegen error if the type can be parsed as a number, since the generated code compiles on Android but not iOS.

shovel-kun avatar May 25 '25 09:05 shovel-kun

How does the generated Kotlin/C++ code look like for Android then? Are you sure that works? Wouldn't it also just use 1 as a property name?

mrousavy avatar May 26 '25 08:05 mrousavy

So I thought a bit about this and I think this would be too complex to really support. There are tons of cases where you can use wrong names, like e.g.;

type SchoolThing = 'class' | 'room'

class will fail to build since it's obviously a reserved keyword in C++, Swift, Kotlin and even JS. Do I have to support that as well?

I feel like it would be cool to have an error thrown for this, but it's just adding code complexity and I'll never cover all cases.

type InvalidThings = ';' | '1' | '     ' | 'struct' | 'enum' | '+' | '....'

mrousavy avatar Jun 05 '25 12:06 mrousavy