// 输入:app.ts
interface User {
name: string;
age: number;
}
function greet(name: string): string {
return "Hello, " + name + "!";
}
function fibonacci(n: number): number {
if (n <= 1) { return n; }
let a: number = 0;
let b: number = 1;
for (let i = 2; i < n; i++) {
let temp = b;
b = a + b;
a = temp;
}
return b;
}
console.log(greet("W3C OS"));
// 输出:main.rs
use std::collections::HashMap;
#[derive(Debug, Clone)]
struct User {
pub name: String,
pub age: i64,
}
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
fn fibonacci(n: i64) -> i64 {
if n <= 1 { return n; }
let mut a: i64 = 0;
let mut b: i64 = 1;
for i in 2..n {
let temp = b;
b = a + b;
a = temp;
}
b
}
fn main() {
let message = greet("W3C OS");
println!("{}", message);
}
---
四、核心 API
compile_to_rust()
将 TypeScript 源码转换为 Rust 代码字符串(无文件 I/O)。
pub fn compile_to_rust(ts_source: &str) -> Result<String> {
if is_ui_dsl(ts_source) {
let tree = parser::parse(ts_source)?;
codegen::generate(&tree)
} else {
ts_transpiler::transpile(ts_source)
}
}
compile()
将 TypeScript 源文件编译为独立的 Rust 项目。
pub fn compile(ts_source: &str, output_dir: &std::path::Path) -> Result<()> {
let is_ui = is_ui_dsl(ts_source);
let rust_code = compile_to_rust(ts_source)?;
std::fs::create_dir_all(output_dir.join("src"))?;
if is_ui {
let cargo_toml = codegen::generate_cargo_toml(output_dir)?;
std::fs::write(output_dir.join("Cargo.toml"), cargo_toml)?;
} else {
let cargo_toml = generate_standalone_cargo_toml()?;
std::fs::write(output_dir.join("Cargo.toml"), cargo_toml)?;
}
std::fs::write(output_dir.join("src/main.rs"), rust_code)?;
Ok(())
}
is_ui_dsl()
启发式检测输入是否为 UI DSL。
fn is_ui_dsl(source: &str) -> bool {
let trimmed = source.trim();
// JSON 格式
if trimmed.starts_with('{') || trimmed.starts_with('[') {
return true;
}
// 检查 W3C OS UI 模式
let has_ui_import = trimmed.contains("@w3cos/std");
let has_component_call = ["Column(", "Row(", "Text(", "Button("]
.iter()
.any(|pat| trimmed.contains(pat));
let has_tsx_component = ["<Column", "<Row", "<Text", "<Button"]
.iter()
.any(|pat| trimmed.contains(pat));
if has_ui_import && (has_component_call || has_tsx_component) {
return true;
}
// 检查主体是否为组件表达式
let body = extract_body(trimmed);
body.starts_with("Column(") || body.starts_with("<Column")
&& !body.contains("function ")
&& !body.contains("const ")
}
---
五、TypeScript 支持范围
✅ 已支持特性
类别
特性
语法
函数、变量、常量、箭头函数
类型
string, number, boolean, 数组,接口,类型别名
控制流
if/else, for, for...in, for...of, while
表达式
二元运算、一元运算、赋值、更新 (++, --)
数据结构
数组字面量、对象字面量
内置函数
console.log() → println!()
数组方法
.push(), .pop(), .length
字符串
模板字面量、字符串拼接
TSX
组件语法、属性、子元素
❌ 不支持的特性
特性
原因
eval()
非 AOT 兼容
innerHTML
XSS 风险,非 AOT 兼容
document.write()
非 AOT 兼容
动态 import()
需要运行时支持
class (部分)
复杂继承未完全支持
泛型
类型擦除后等价 Rust
---
六、类型推断系统
编译器使用静态类型推断将 TypeScript 类型映射为 Rust 类型:
TypeScript
Rust
string
String
number
i64 / f64
boolean
bool
number[]
Vec
string[]
Vec
T[]
Vec
{ name: string }
struct { name: String }
T \
null
Option
any
serde_json::Value
Map
HashMap
推断示例
// TypeScript
let count: number = 42; // → let count: i64 = 42;
let name: string = "W3C"; // → let name: String = "W3C".to_string();
let items: number[] = [1, 2, 3]; // → let items: Vec<i64> = vec![1, 2, 3];
interface User {
name: string;
age: number;
email?: string;
}
// → struct User { pub name: String, pub age: i64, pub email: Option<String> }
---
七、代码生成策略
UI DSL 代码生成
fn gen_node(node: &Node, depth: usize, signal_names: &[&str]) -> String {
let indent = " ".repeat(depth + 1);
let style_code = gen_style(&node.style, depth + 1);
match &node.kind {
NodeKind::Text(content) => {
let text = node.text.as_deref().unwrap_or(content.as_str());
format!("{indent}Component::text({text:?}, {style_code})")
}
NodeKind::Button(label) => {
let lbl = node.label.as_deref().unwrap_or(label.as_str());
if let Some(ref action_str) = node.on_click {
let action = gen_event_action(action_str, signal_names);
format!("{indent}Component::button_with_click({lbl:?}, {style_code}, {action})")
} else {
format!("{indent}Component::button({lbl:?}, {style_code})")
}
}
NodeKind::Column => {
let children_code = if node.children.is_empty() {
"vec![]".to_string()
} else {
let items: Vec<String> = node.children
.iter()
.map(|c| gen_node(c, depth + 2, signal_names))
.collect();
format!("vec![\n{},\n{indent}]", items.join(",\n"))
};
format!("{indent}Component::column({style_code}, {children_code})")
}
// ...
}
}
通用 TS 代码生成
fn transpile_for(&mut self, for_stmt: &ForStmt) -> Result<()> {
// 检测:for (let i = 0; i < N; i++) → for i in 0..N
if let Some(range) = detect_range_for(for_stmt) {
self.push_indent();
self.push(&format!("for {} in ", range.var));
self.transpile_expr(&range.start)?;
self.push("..");
self.transpile_expr(&range.end)?;
self.push(" {\n");
self.indent += 1;
self.transpile_stmt_body(&for_stmt.body)?;
self.indent -= 1;
self.line("}");
return Ok(());
}
// 通用 for → while 循环
// ...
}
#[test]
fn compile_general_ts_showcase() {
let input = r#"
interface User {
name: string;
age: number;
email?: string;
}
function greet(name: string): string {
return "Hello, " + name + "!";
}
function fibonacci(n: number): number {
if (n <= 1) { return n; }
let a: number = 0;
let b: number = 1;
for (let i = 2; i < n; i++) {
let temp = b;
b = a + b;
a = temp;
}
return b;
}
console.log(greet("W3C OS"));
"#;
let rust = compile_to_rust(input).unwrap();
assert!(rust.contains("struct User"));
assert!(rust.contains("fn greet("));
assert!(rust.contains("fn fibonacci("));
assert!(rust.contains("fn main()"));
assert!(rust.contains("for i in"));
assert!(rust.contains("println!"));
}