Export TypeScript Definitions For Game Components
zicklag opened this issue · 11 comments
It should be possible for us to export TypeScript definitions for all of the types that we can find in the Bevy type registry. That would allow us to give type definitions for all the components you can interact with in scripts.
We may want to come up with a way that you could import the type definition for Vec3
for instance, and then it could contain the full type name in it so that you could use it to extract the ComponentInfo
and ComponentId
for that type.
This needs some thought, but I think we should be able to make a nice workflow.
Maybe they could be autogenerated using the static TypeInfo
if available https://docs.rs/bevy_reflect/latest/bevy_reflect/enum.TypeInfo.html
Yeah, that was what I was thinking. And if anything is dynamic it would just map to any
.
It's not possible to associate values with types in typescript, right?
It would be cool if
type Transform = {
translation: Vec3;
// ???
};
console.log(Transform.type_name) // the type name we can look up in the type registry
would work somehow.
Like an associated constant in rust
Yeah, unfortunately the closest thing I can find so far is a class with static field:
class Velocity {
static typeName: string = "breakout::Velocity";
0: Vec3
}
class Vec3 {
static typeName: string = "bevy::math::Vec3";
x: number;
y: number;
}
This works, but unfortunately because it's an actual class and not done at TypeScript compile time, it requires that we actually import the generated bindings. We can't put them in an "ambient context" like the rest of the types in lib.bevy.d.ts
.
That might require that we find a way to mange manage imports in scripts, but I did want to do that anyway, and I don't think it's going to be incredibly difficult, now that I got export rewriting working in #11.
That alone can't make
world.getResource<Time>();
work, right?
Because we have no instance of the type available.
Maybe
function getResource<T>(ty: BevyType<T>) {}
interface Time {
delta_seconds: number;
}
const Time: BevyType<Time> = { typeName: "..." };
let time = world.getResource(Time);
// Time type is inferred
I don't know if typescripts type inference is good enough for that, and if it has separate type and value namespaces.
Update: typescripts inference is strong enough.
This works:
type BevyType<T> = { typeName: string; };
type Time = {
seconds: number,
};
const Time: BevyType<Time> = { typeName: "bevy_core::time::Time" };
function getResource<T>(type: BevyType<T>): T {
throw new Error();
}
let resource = getResource(Time);
resource.seconds;
Oh sweet! That's great.
Exporting all types in a quick and hacky way is pretty easy:
https://github.com/jakobhellermann/bevy_reflect_ts_type_export/blob/main/generated/types.ts
And working with typed APIs is super nice:
bevy_mod_js_scripting/assets/scripts/breakout.ts
Lines 12 to 23 in 5b2df5e
TS can just overload two method signatures, and the deno op can deal with either.
bevy_mod_js_scripting/src/runtime/js/index.d.ts
Lines 53 to 54 in 5b2df5e