phoenix-ru / fervid

All-in-One Vue compiler written in Rust
https://phoenix-ru.github.io/fervid/
Apache License 2.0
371 stars 9 forks source link

Infer `ref` and `computed` TypeScript types for smarter inlining #9

Open phoenix-ru opened 9 months ago

phoenix-ru commented 9 months ago

Situation

When using <script setup lang="ts"> we can make assumptions regarding binding types. For instance, we can confidently infer the types of bindings in this example:

<script setup lang="ts">
import { ref, computed } from 'vue'

const foo = ref('Hello')
const bar = ref(1)
const baz = computed<number>(() => bar.value * 2)
</script>

Proposal

fervid can trust the user's TypeScript setup to catch type errors. In the future, when stc is mature enough, it will be used for type inference and checking.

Knowing the binding TS type, we can further optimize the generation of Interpolations and SSR attributes: const msg = ref('') // string

What Mode Current generation Proposal generation
{{ msg }} CSR _toDisplayString(msg.value) msg.value
{{ msg }} SSR _ssrInterpolate(msg.value) msg.value
:value="msg" SSR _ssrRenderAttr("value", msg.value) `value="${msg.value}"`

By having the knowledge of types we can omit unnecessary runtime checks and also ship less code.

Possible implementation

The transformer already detects Vue-specific symbols, such as ref and computed. We can extend the analysis to also visit the value (second priority) or the type annotations (first priority) and store this information along with the BindingTypes.

Considering the fact that TS types are complex and inference may not be trivial, the TS type must be an optional hint for the compiler. When no such type can be inferred (or when outside TS), the compiler should fall back to default code generation.