Support for custom bounds
I need to be able to define custom bounds, exactly like #[serde(bounds)].
E.g.:
trait EntityKind {
type KeyKind;
}
#[derive(serde::Serialize, typescript_type_def::TypeDef)]
pub struct EntityKey<Kind> {
some_accessory_field: usize,
kind: Kind,
}
#[derive(serde::Serialize, typescript_type_def::TypeDef)]
pub struct Entity<Kind> {
some_accessory_field: usize,
kind: Kind,
}
#[derive(serde::Serialize, typescript_type_def::TypeDef)]
#[serde(bound = "Kind: serde::Serialize, Kind::KeyKind: serde::Serialize")]
#[type_def(bound = "Kind: typescript_type_def::TypeDef, Kind::KeyKind: typescript_type_def::TypeDef")]
struct ConcreteEntity<Kind: EntityKind> {
key: EntityKey<Kind::KeyKind>,
value: Entity<Kind>,
}
This code won't work, you get a duplicate field error on second bound definition.
Doing everything in a single bound, like
#[derive(serde::Serialize, typescript_type_def::TypeDef)]
#[serde(
bound = "Kind: serde::Serialize + typescript_type_def::TypeDef, Kind::KeyKind: serde::Serialize + typescript_type_def::TypeDef"
)]
struct ConcreteEntity<Kind: EntityKind> {
key: EntityKey<Kind::KeyKind>,
value: Entity<Kind>,
}
doesn't work anyway, because bound is ignored by TypeDef proc-macro.
At the moment the only workaround I've found is to write TypeDef trait implementation by hand.
Maybe I'm missing something, but these bounds seem unnecessary? The TypeDef derive macro already adds TypeDef bounds to all the generic arguments, and the Serialize bound isn't needed for implementing TypeDef. Does this work?
#[derive(serde::Serialize, typescript_type_def::TypeDef)]
#[serde(bound = "Kind: serde::Serialize, Kind::KeyKind: serde::Serialize")]
struct ConcreteEntity<Kind: EntityKind> {
key: EntityKey<Kind::KeyKind>,
value: Entity<Kind>,
}
Tried it myself, I see the issue, the Kind::KeyKind type needs a TypeDef bound. Yeah this seems like an analogous problem to what the bound option for serde is solving. I can work on adding this.
Actually, this brings up an interesting problem with how associated types are handled. How would you write a Typescript generic type for ConcreteEntity that's equivalent to the Rust one?
type ConcreteEntity<Kind> = {
key: EntityKey<?>,
value: Entity<Kind>,
}
Typescript has no equivalent for Kind::EntityKind since it does not have associated types.
I'm curious what the hand-written type definition you had looked like.
That's a good question... I'm kinda alien to the typescript world, I'm just trying to expose data from a WASM module and let frontend people live happily with it...
In facts this code generates a wrong definition:
trait EntityKind {
type KeyKind;
}
#[derive(serde::Serialize, typescript_type_def::TypeDef)]
pub struct EntityKey<Kind> {
some_accessory_field: usize,
kind: Kind,
}
#[derive(serde::Serialize, typescript_type_def::TypeDef)]
pub struct Entity<Kind> {
some_accessory_field: usize,
kind: Kind,
}
#[derive(serde::Serialize, typescript_type_def::TypeDef)]
#[serde(bound = "Kind: serde::Serialize, Kind::KeyKind: serde::Serialize")]
struct ConcreteEntity<Kind: EntityKind>
where
Kind::KeyKind: typescript_type_def::TypeDef,
{
key: EntityKey<Kind::KeyKind>,
value: Entity<Kind>,
}
#[derive(serde::Serialize, typescript_type_def::TypeDef)]
struct ConcreteEntityKind1 {}
impl EntityKind for ConcreteEntityKind1 {
type KeyKind = usize;
}
#[derive(serde::Serialize, typescript_type_def::TypeDef)]
struct ConcreteEntityKind2 {}
impl EntityKind for ConcreteEntityKind2 {
type KeyKind = String;
}
generated definition:
// AUTO-GENERATED by typescript-type-def
export default types;
export namespace types {
export type Usize = number;
export type EntityKey<Kind> = {
"some_accessory_field": types.Usize;
"kind": Kind;
};
export type Entity<Kind> = {
"some_accessory_field": types.Usize;
"kind": Kind;
};
export type ConcreteEntityKind1 = {
};
export type ConcreteEntity<Kind> = {
"key": types.EntityKey<types.Usize>;
"value": types.Entity<Kind>;
};
export type ConcreteEntityKind2 = {
};
}