kotlin-react-routerを6.3->6.7にする時にRouteで躓いた

## 要約
kotlin-react-routerを6.3.0-pre491から6.7.0-pre492にする段階で`Route`関数のラムダ式引数内で`path`や`element`が使えなくなるが、`this as PathRouteProps`でキャストすれば回避できる。

さらに先のバージョン(6.17.0-pre635)ではこの回避策も無効になる([続編参照](https://qiita.com/sskki/items/0b191dc9cdc120cf20e8))。

## 環境
+ Ubuntu 20.04LTS
+ IntelliJ IDEA 2023.1.4 (Community Edition)
+ Kotlin/JS 1.8.20(IRコンパイラ)
+ Kotlin Wrappers 1.0.0-pre.598
+ kotlin-react-router-dom 6.14.1-pre.598
+ gradle 8.1.1

## 動機
2023年7月現在[Kotlin Wrappers](https://github.com/JetBrains/kotlin-wrappers#experimental-ir-backend)に、"React wrappers in particular heavily relied on specific characteristics of the default backend, which might make your current code incompatible with the new IR backend."と書かれているので、LEGACYコンパイラのままにしてきた。しかし、Kotlin 1.9がリリースされLEGACYコンパイラが廃止される流れになっているので、コンパイラの切り替えとライブラリの更新を一気に行おうと思った。

## 現象
Kotlin Wrappersを1.0.0-pre.348から1.0.0-pre.598に更新し、build.gradle.ktsでコンパイラの指定を`LEGACY`から`IR`に変更した。これに合わせてkotlin-react-router-domのバージョンも6.3.0-pre.348から6.14.1-pre.598に変更した。

ソースコードの変更は`import react.dom.html`を`import web.html`に変更するといった対応で済むものが多かったが、React Routerに関しては


``` kotlin
import react.FC
import react.Props
import react.router.Route
import react.router.Routes
import react.router.dom.BrowserRouter

val Main = FC<Props> {
    BrowserRouter {
        Routes {
            Route {
                path = "sample.html"
                element = createElement(Sample)
            }
        }
    }
}
```
のように書いて問題なく動作していたのが、`path`や`element`の所でエラーが出るようになった。

## 調査
### Kotlin Wrappersのソースコード
`path`や`element`は`react.router.RouteProps`由来とのことで、該当部分のソースを参照すると、
```kotlin
sealed external interface RouteProps : react.Props /* export type RouteProps = PathRouteProps | LayoutRouteProps | IndexRouteProps; */
```
となっている。これが、ライブラリ更新前だと、
```kotlin
external interface RouteProps : react.PropsWithChildren {
    var caseSensitive: Boolean?
    override var children: react.ReactNode?
    var element: react.ReactNode?
    var index: Boolean?
    var path: String?
}
```
となっており、更新に際して属性の指定が消されてしまっている。

### React Routerのソースコード
これだけだと解決策が浮かばないので[React Routerのソース](https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/components.tsx)を探ってみた。

```tsx
export type RouteProps = PathRouteProps | LayoutRouteProps | IndexRouteProps;
```
はKotlin側のソースでコメントアウトされていた通り。そして`PathRouteProps`, `LayoutRouteProps`, `IndexRouteProps`はそれぞれ、

+ `PathRouteProps`: `path`や`element`がある。
+ `LayoutRouteProps`: `PathRouteProps`と同等。
+ `IndexRouteProps`: `PathRouteProps`の`index`をtrueにしたもの。

といった状態であった。ちなみに`PathRouteProps`に対応して`PathRoute`がある訳ではなく、あるのは`Route`だけの模様。

### 推定される原因と解決法
`RouteProps`の属性情報が消された上に、`PathRouteProps`, `LayoutRouteProps`, `IndexRouteProps`のどれであるか特定する方法がないので、`path`や`element`にアクセスできない。

逆に言うと`PathRouteProps`, `LayoutRouteProps`, `IndexRouteProps`のどれであるか特定できれば`path`や`element`にアクセスできるようになりそう。

## 解決
`Route`の型引数に`PathRouteProps`を指定して解決を図ろうとしたが、うまく行かなかった。以下のように`this as PathRouteProps`でキャストを強制したらこれまで通り動作するようになった。

```kotlin
import react.FC
import react.Props
import react.router.PathRouteProps
import react.router.Route
import react.router.Routes
import react.router.dom.BrowserRouter

@Suppress("UNCHECKED_CAST_TO_EXTERNAL_INTERFACE")
val Main = FC<Props> {
    BrowserRouter {
        Routes {
            Route {
                this as PathRouteProps
                path = "sample.html"
                element = createElement(Sample)
            }
        }
    }
}
```

### IndexRouteProps
前述の通り`react.router.IndexRouteProps`というものがあるが、`index = true`の`Route`でこれにキャストしてもうまく行かなかった。
代わりに上記`PathRouteProps`にキャストした後、`path`を設定せずに`index = true`としたら問題なかった。

## 考察
### ライブラリを更新しないという選択も
ちなみに、kotlin-react-router-domのバージョンを6.3.0に据え置いたままコンパイラをIRにして他のReact関連のラッパーを更新しても、自分の使用している範囲では問題がなかった。

いちいちキャストが必要というのは明らかに使いづらいので、もしかしたら改善されるかもしれない。という希望的観測のもと、もうしばらく放置しておくというのは必ずしも悪い考えではないと思う。

### 発生時期など
GitHubの履歴によると、2023年2月上旬の6.3.0-pre.491から6.7.0-pre.492への変更でフォルダ構成と共に色々変わってこうなったようだ。

kotlin-react-router-domの以前のreadme.mdにはサンプルコードが載っていたのだが、上記更新の際に消えてしまっている。発生する問題の説明がないのも頂けないが、せめて動作するサンプルコードくらい載せてくれればここまで悩まずに済んだ。

自動生成のコードのようなので、開発側も自分自身で使っていないのかもしれない。

## 改訂履歴(表現の修正などは除く)
+ 2023/5/14: 挫折してしばらく放置
+ 2023/7/23: ライブラリの更新に成功
+ 2023/7/24: 初版作成
+ 2024/8/4: 続編へリンク