jhugman / uniffi-bindgen-react-native

A uniffi bindings generator for calling Rust from react-native
Other
0 stars 0 forks source link

Types imported from foreign packages need to be aliased to avoid shadowing #67

Closed zzorba closed 1 week ago

zzorba commented 3 weeks ago

Okay, so this is a bit confusing. We have a local enum:

use matrix_sdk_ffi::sync_service::SyncServiceState;

#[derive(Clone, uniffi::Enum)]
pub enum ActionType {
   ...

    /// Sync service state reported by the Matrix client.
    SyncServiceState(SyncServiceState),
}

As you can see, it has a data field that is from a different package, but it has the same name for the 'enum'. Totally legal rust code, but, when typescript interfaces get generated: 1) it does import it from matrix_sdk_ffi

import {
  SyncServiceState,
} from './matrix_sdk_ffi';

But then it ends up not using it, because of type shadowing:

// Inside of ActionType
/**
   * Sync service state reported by the Matrix client.
   */
  class SyncServiceState
    extends UniffiEnum
    implements SyncServiceState_interface
  {
    readonly tag = ActionType_Tags.SyncServiceState;
    readonly inner: Readonly<SyncServiceState_data>;
    constructor(v0: SyncServiceState) {
      super('ActionType', 'SyncServiceState', 9);
      this.inner = Object.freeze([v0]);
    }

    static new(v0: SyncServiceState): SyncServiceState {
      return new SyncServiceState(v0);
    }

    static instanceOf(obj: any): obj is SyncServiceState {
      return obj.tag === ActionType_Tags.SyncServiceState;
    }
  }

The constructor should be referring to the inner type, not itself.

This causes the unpacking functions to produce typescript errors, and the type checking to generally be a bit wonky here (even though it probably works, since the code is designed to access the data correctly, even if it is not legal typescript).

I think the fix here is to alias the types on import with some generated qualification of the package name, i.e.

  import {
  SyncServiceState as _MatrixSdkFFI_SynceServiceState,
} from './matrix_sdk_ffi';

And then when referring to the foreign type, you always use the fully qualified 'alias' name.

zzorba commented 3 weeks ago

This snippet of rust will reproduce the problem in the typescript file:


#[derive(uniffi::Enum, Clone, Debug)]
pub enum InnerType {
    Foo,
    Bar,
}

#[derive(Clone, uniffi::Enum)]
pub enum WrappingEnum {
    TotallyFine,
    InnerType(InnerType),
}

Argument of type 'import("/Users/daniel/filament/packages/rn-diode/src/generated/diode").InnerType' is not assignable to parameter of type 'InnerType'.ts(2345)

jhugman commented 3 weeks ago

I'm fairly sure that this is fixed by #70

jhugman commented 1 week ago

Closing, fixed by #70