tsify-next を使っていると特定の型名に対して想定していない型情報が生成されることがあります。
例えば Path
, Range
, Cow
などがそうです。
// Rust pub struct Path { b: bool, s: String, } #[derive(Tsify)] pub struct Range<T> { _t: T, b: bool, s: String, } #[derive(Tsify)] pub struct Cow<T> { _t: T, b: bool, s: String, }
コンパイルすると次のような型が生成されます。
// .d.ts export interface Path { b: boolean; s: string; } export interface Range<T> { _t: T; b: boolean; s: string; } export interface Cow<T> { _t: T; b: boolean; s: string; }
ここまでは何もおかしなことはなく、想定している通りですね。
問題はこれらの型を struct のフィールドに対して指定したときにおこります。
// Rust #[derive(Tsify)] pub struct A { path: Path, range: Range<()>, cow: Cow<()>, }
コンパイルすると想定していない結果になります。
// .d.ts export interface A { path: string; range: { start: null; end: null }; cow: null; }
さきほど定義した Path
や Range
や Cow
が引用されて欲しい場所がそれぞれ string
, { start: null; end: null }
, null
になってしまっています。
Rust の標準の型と混同される
Rsut には Path
, Range
, Cow
という型が標準ライブラリで定義されています。
ただしデフォルトの名前空間には読み込まれていないため、参照するにはフルパスで記述するか use 句を書いておく必要があります。
// Rust use std::path::Path; use std::ops::Range; use std::borrow::Cow;
デフォルトの名前空間に読み込まれていないということは、ユーザー独自の型名に Path
, Range
, Cow
を使用しても問題はないということです。
ただし、Tsify では問題になります。
Tsify では Path
, Range
, Cow
などのキーワードが現れるとそれらを std::path::Path
, std::ops::Range
, std::borrow::Cow
だと解釈して型情報を生成します。
実際、独自定義型ではなく標準型の方を使ってみると、
// Rust #[derive(Tsify)] pub struct B<'a> { path: Box<std::path::Path>, range: std::ops::Range<usize>, cow: std::borrow::Cow<'a, str>, }
// .d.ts export interface B { path: string; range: { start: number; end: number }; cow: string; }
これなら生成結果に違和感はありません。
Tsify には予約された型名がある
ここまでで見たように Tsify は特定の型名を標準ライブラリで定義された型だと思い込むという問題があります。 コードで言うと下記のあたりで型名がハードコードされています。
簡単な回避策は独自定義型のほうの型名を変えてしまうことです。
例えば接頭辞として My
をつけて、
// Rust pub struct MyPath { b: bool, s: String, } #[derive(Tsify)] pub struct MyRange { b: bool, s: String, } #[derive(Tsify)] pub struct MyCow { b: bool, s: String, } #[derive(Tsify)] pub struct A { path: MyPath, range: MyRange, cow: MyCow, }
このようにすると、
// .d.ts export interface MyPath { b: boolean; s: string; } export interface MyRange { b: boolean; s: string; } export interface MyCow { b: boolean; s: string; } export interface A { path: MyPath; range: MyRange; cow: MyCow; }
このように独自定義の型を引用したうえで正しく型情報が生成されます。
まとめ
Path
, Range
, Cow
などはユーザーが独自に型を定義するときにも型名として使ってしまいがちです。
Tsify においては予約済みの型名なので注意が必要ですね。
私からは以上です 🐄