There is no sanctioned/correct way. TypeId is not supposed to be sent between processes or address spaces. And the type is definitely not going to remain layout-compatible with u64 forever, because issue 10389 needs to be addressed. (See also.)
It’s fantastically unsafe, because you need to know that both sides are actually running the same binary: I don’t know what all goes into the TypeId hash, and therefore what might make it change— Even recompiling identical source code might do it.
I guess one question I have is: is TypeID determined 100% at compile time, or is it partially determined at runtime ?
Because I can guarantee that both index.html and webworker are running the same identical *.wasm file, but the runtime environments might be slightly different as one is initiated in a webworker and another is initiated in index.html
Implementing something like typtag, for serializing / deserializing dyn trait objects, only to be sent between index.html/main.wasm and webworker/main.wasm .
So, in particular, the serializer is going to package the object as (u64 = typeid, data = Vec<u8>), then the deserializer is going to look at the u64 to know which deserializer to call.
You're going to have to manually create a list of types to lookup the TypeIds anyway aren't you? You could just as easily make it a string or a number you chose if so
With https://crates.io/crates/inventory we don't have to define all the types at once, we can define them locally whenever. If we manually assign a string / number, there is a (tiny) chance of collision. With TypeID, it's (afaik) guaranteed to be unique.
It is an explicit goal to make TypeId not the same size as u64 and break the unsound uses in the wild (see @cole-miller's links). So I suggest you not go the u64 route. In fact, the fix involves adding more information behind a pointer, so serializing the bytes of TypeId won't work either.
If you have a fixed set of types, you could sort their TypeIds and use the index for serialization.
Whatever you settle on, if you're relying on TypeId, make sure everything used the same compiler version and invocation flags. Probably this means use the same executable (which you said you were doing, so good).
I think just detecting a duplicate and panicking at launch would be a reasonable way to handle that, rather than trying to do wacky unsafe shenanigans with TypeId
I don't think the inventory crate works on wasm32-unknown-unknown because WebAssembly doesn't let you do the same __attribute__((constructor)) trickery where you can automagically set one or more functions to be executed on startup. Or at least, Rust has no way to tel LLVM to do the right thing.
Instead of doing unreliable trickery with TypeId and hoping for the best, and given you have complete control over both sides, could you use something like the typename crate to get a stable identifier (the type's fully qualified name) for your type tag?
For example, amongst the strings that type_name::<Option<String>>() might return are "Option<String>" and "std::option::Option<std::string::String>".
The returned string must not be considered to be a unique identifier of a type as multiple types may map to the same type name. Similarly, there is no guarantee that all parts of a type will appear in the returned string: for example, lifetime specifiers are currently not included. In addition, the output may change between versions of the compiler.
The "not unique identifier" part makes this not a good choice.