wulf / tsync Goto Github PK
View Code? Open in Web Editor NEWSynchronize rust and typescript types!
License: Other
Synchronize rust and typescript types!
License: Other
The following example, found in test/const/rust.rs does not compile for me:
#[tsync]
const SERDE_JSON_2: serde_json::Value = json!({ "a": "b" });
I get this error, among others:
mutable references are not allowed in constants
From my understanding, the constructor for serde_json::Value is not const, so using json! macro to initialize a const macro is not possible. Is there some way to successfully compile the const JSON?
Currently, it seems that tuples (or at least, optional tuples) are output as 'unknown' - TypeScript has a tuple type, so it should be fairly easy to convert between Rust tuples and TypeScript tuples?
#[tsync]
struct HasTuple {
foo: i32,
bar: Option<(String, i32)>,
}
// Current output
interface HasTuple {
foo: number;
bar?: unknown;
}
// Ideal output
interface HasTuple {
foo: number;
bar?: [string, number]; // TypeScript tuple syntax
}
If a proc-macro generates a struct, those generated structs are not exported, even if the #[tsync]
annotation is on the generated struct. Is this possible to somehow accomplish with tsync's current architecture?
Thanks for this fantastic library!
Typescript has the "Optional parameters" syntax for fields that implicitly add the undefined
type to a field.
Instead of
interface Foo {
id: number,
bar: string|undefined
}
you can do the following:
interface Foo {
id: number,
bar?: string
}
bar
in the second case is still of type string|undefined
, but then it is possible to omit field bar
from instances completely and typescript will not error out.
Instead of explicitly creating a Foo
like:
let foo: Foo = {
id: 42
bar: undefined
}
You can do:
let foo: Foo = {
id: 42
}
Is this a possibility? Or perhaps a possible run flag?
Is it possible to have Enum variants that take a self named struct parameter and output as types?
#[tsync]
enum Message {
MyStruct1(MyStruct1),
MyStruct2(MyStruct2),
}
The ideal output: type Message = | MyStruct1 | MyStruct2;
where the structs are types, not strings
.
This would allow easy structuring of JSON in Rust and Destructing in TypeScript, Example:
#[tsync]
#[derive(Serialize)]
struct MyStruct1 {
data1: bool,
data2: MyStruct2,
}
#[tsync]
#[derive(Serialize)]
struct MyStruct2 {
data1: String,
data2: i32,
}
#[tsync]
#[derive(Serialize)]
enum Message {
MyStruct1(MyStruct1),
MyStruct2(MyStruct2),
}
fn main() {
let message = Message::MyStruct2(MyStruct2 {
data1: "hello".to_string(),
data2: 42,
});
let json = serde_json::to_string(&message).unwrap();
println!("Send to frontend: {}", json);
// Output: {"MyStruct2":{"data1":"hello","data2":42}}
}
I have a type which looks like the following:
#[tsync]
#[derive(SomeDieselStuff, Serialize)]
pub struct Foo {
pub field1: Type1,
pub field2: Type2,
#[serde(rename = "type")]
pub type_: FooType, // called type_ to avoid diesel errors caused by using r#type
// although as it turns out r#type is also not handled by tsync
}
In the generated output, I get an interface containing type_
and not containing type
, where I would expect the interface to contain type
instead of type_
.
This should probably have its own issue, but using r#type
causes the same issue - the generated typescript output would then contain a member called r#type
(which is a syntax error in TypeScript, aside from simply being wrong - serde serialises this without the r#
as would be expected by the identifier parsing rules)
Case:
use tsync::tsync;
#[tsync]
pub struct Test(String);
fn main() {
unimplemented!();
}
Output:
thread 'main' panicked at /home/archeoss/.local/share/cargo/registry/src/index.crates.io-6f17d22bba15001f/tsync-2.0.1/src/to_typescript/structs.rs:30:38:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Hi,
Thanks for the great work!
Would you be interested in adding conversion for const
Items that are of a simple type into Typescript statements like a string, number and maybe a serde_json::Value where the RHS has to json!
invocation ? This overall would make writing my tests easier with fully typed data-attributes and increase general ergonomics.
const SOME_FLAG: u32 = 0; ---> const SOME_FLAG = 0;
const SOME_JSON: serde_json::Value = serde_json::json!({
"name": "John Doe",
"age": 43,
"phones": [
"+44 1234567",
"+44 2345678"
]
})
--->
const SOME_JSON = {
"name": "John Doe",
"age": 43,
"phones": [
"+44 1234567",
"+44 2345678"
]
};
Enums/Variants would also be great however I would be unsure of what would be best I was thinking something like:
#[tsync(Case::ScreamingSnake)]
enum EnumType {
CaseOne
CaseTwo(i32),
CaseThree {
x: i64,
y: i64
}
}
``` goes to
```typescript
type EnumType = "CaseOne" | [number] | { type: "CaseThree", x: number, y: number }
I don't usually end up mixing tuple and named structs in enums so unsure of the best way to preserve "CaseTwo":
type EnumType = "CaseOne" | ["CaseTwo", number] | { type: "CaseThree", x: number, y: number }
or just convert to dictionary and probably the better way.
type EnumType = "CaseOne" | { type: "CaseTwo", 0: number} | { type: "CaseThree", x: number, y: number }
Very happy to take a crack at both in a PR. Let me know your thoughts!
Currently comments are generated as line comments.
// This is a comment on the type
interface Foo {
// This is a comment on a property
bar: boolean
// This is a multi
// line comment
baz: boolean
}
These types of comments are not picked up by intellisense (in vscode + other tools)
If comments are generated as jsdoc blocks instead, then intellisense will work
/**
* This is a comment on the type
*/
interface Foo {
/** This is a comment on a property */
bar: boolean
/**
* This is a multi
* line comment
*/
baz: boolean
}
I'd be happy to contribute a PR if you agree with the change and can point me in the right direction!
Lines 65 to 67 in 2323480
BTW: v1.7.0 works fine.
The current CI workflow file is invalid, the test
job depends on the build
job, but there is no build
job so the workflow always fails.
I would like to support rust_decimal's Decimal
type. Depending on configuration, this type can be represented in serde as either a float or a string. This is further complicated by options covering the whole crate or just specific fields. While generating TypeScript types via tsync
, I would like to somehow specify which representation to use.
Currently I can create a separate module exclusively for inclusion in tsync
and export custom type mappings there, however I would prefer to erase the type entirely.
Alternatively, I can fork the project and and add the additional type to convert_type
directly as a global type mapping. This produces results closer to what I want, but requires more work to maintain.
Neither of these solutions would help the per-field case.
I am wondering about adding a field parameter to override types in-line, something like:
#[derive(Debug, Serialize, Deserialize)]
#[tsync]
pub struct Foo {
name: Option<String>,
#[tsync(type = "number")]
quantity: Decimal,
}
Currently the serde flatten attribute is not supported. It would be nice to have this code:
#[tsync]
#[derive(Serialize)]
struct Outter {
id: String,
#[serde(flatten)]
inner: Inner,
}
#[tsync]
#[derive(Serialize)]
struct Inner {
value: String,
}
generate something like this:
type Outter = Inner & {
id: string;
}
interface Inner {
value: string;
}
Also, enum support would be ideal. I'm open to other options for how the outputted TS would look, I'm only suggesting the intersection type because it would be easier for it to work with enums since they are usually defined with the type
keyword.
Hi, is there any way to do const enums?
For example,
enum Test {
Foo,
Bar
}
becomes
const enum Test {
Foo,
Bar
}
or..
enum Test {
Foo = 5,
Bar = 6
}
becomes
const enum Test {
Foo = 5,
Bar = 6
}
Currently it seems like the enums generated do not have the const prefix in the generated Typescript code. I only use const enums for my project
Hello again!
In my project, I use a lot of enums, and it is often desirable to match on the variants.
As a result, it'd be nice if something like this:
#[tsync]
struct AppleData {
crunchy: bool
}
#[tsync]
struct BananaData {
size: i32
}
#[tsync]
struct CarrotData {
color: String
}
#[tsync]
enum Fruit {
Apple(AppleData),
Banana(BananaData),
Carrot(CarrotData),
}
Converted to something like this:
export interface AppleData {
crunchy: boolean
}
export interface BananaData {
size: number
}
export interface CarrotData {
color: string
}
const enum FruitKinds {
Apple,
Banana,
Carrot
}
export interface CaseFruitApple {
kind: FruitKinds.Apple;
data: AppleData;
}
export interface CaseFruitBanana {
kind: FruitKinds.Banana;
data: BananaData;
}
export interface CaseFruitCarrot {
kind: FruitKinds.Carrot;
data: CarrotData;
}
export type Fruit =
| CaseFruitApple
| CaseFruitBanana
| CaseFruitCarrot;
My reasoning:
It provides the frontend code with everything it needs. Many functions may only be interested in the case for the banana, and can take just that as a parameter. It makes it so that none of the frontend types are anonymous anymore. It also provides an enum of all the variants as well, since that is often useful. And it allows for a full conversion of the ADT pattern, such that you can narrow the types in the frontend code. For example:
function renderApple(apple: AppleData) {
// type-safe and narrowed to an apple
}
function renderBanana(apple: BananaData) {
// type-safe and narrowed to a banana
}
function renderCarrot(apple: CarrotData) {
// type-safe and narrowed to a carrot
}
switch (fruit.kind) {
case FruitKinds.Apple: return renderApple(fruit.data);
case FruitKinds.Banana: return renderBanana(fruit.data);
case FruitKinds.Carrot: return renderCarrot(fruit.data);
}
Thoughts?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.