# TypeScript

由於 Alas 採用 TypeScrtip (以下簡稱TS) 編寫,因此擁有 TS 的完整支援,但 Model 本身由於應用模式都不一樣,所以仍然需要個別定義型態。

注意

盡可能別使用 addModel 進行 Model 的新增,這對 TS 的友善度極差。

# 基本宣告

import type {
    ModelOptions,
    ModelStructure,
    ContainerOptions,
    ContainerStructure
} from 'alas'

// 定義 Model 結構
type ProfileStructure = ModelStructure<{
    model: {
        name: string
        // 定義 views 必須使用 $v
        $v: Readonly<{
            name: string
        }>
    }
}>
const profileOptions: ModelOptions<ProfileStructure> = {
    body: {
        name: []
    },
    views: {
        name: self => self.name
    }
}
// 定義 Container 結構
type UserStructure = ContainerStructure<{
    models: {
        profile: ProfileStructure
    }
}>
const UserOptions: ContainerOptions<UserStructure> = {
    models: {
        profile: profileOptions
    }
}
// 定義 Core 結構
type Containers = {
    user: UserOptions
}
const alas = new Alas<Containers>({
    containers: {
        user
    }
})

# Container Types

Container Types 是一種快速獲取 Model 型態的方法,而不需要透過繁雜的路徑獲取類別:

import Alas, { ContainerTypes } from 'alas'

// 如上述例子...

type AlasTypes = ContainerTypes<Containers>
const alas = new Alas<Containers>({
    containers: {
        user
    }
})
function showUsername(profile: AlasTypes['user']['profile']['model']) {
    console.log(profile.name)
}
const profile = alas.make('user', 'profile').$init({ name: 'james' })
showUsername(profile) // james

# Vue 的難處

當我們用 Vue3 進行 reactive 獲取響應物件的時候,傳遞的資料會被轉換掛上一層 Proxy ,這將導致型態轉變使得型態驗證錯誤。

這意味著就算透過 Container Types 指定方法的參數也無法相容 reactive 中宣告的 Model :

import { reactive } from 'vue'
function showUserName(user: AlasTypes['user']['profile']['model']) {
    console.log(user.name)
}
const user = alas.make('user', 'profile')
const state = reactive({
    user
})
// 由於 user 已經被轉換型態,所以無法通過型態驗證
showUserName(state.user)

我們採用了一種解決方案用於複寫原本的 reactive 的型態轉換方案:

import { reactive } from 'vue'
function data<T>(data: T) {
    return reactive(data as any) as T
}
function showUserName(user: AlasTypes['user']['profile']['model']) {
    console.log(user.name)
}
const user = alas.make('user', 'profile')
const state = data({
    user
})
showUserName(state.user)

警告

雖然這樣能確保資料類型相同,但必須得知 reactive 實際上是返回了一個不一樣類型的新物件,下例便是驗證的結果。

import { reactive } from 'vue'
const user = {
    profile: {
        name: 'james'
    }
}
console.log(user.profile === user.profile) // true
const state = reactive({
    user
})
console.log(state.user.profile === user.profile) // false

本章節只是敘述了一部分的宣告方式,你可以透過接下來的結構與操作單元中得知如何進行其他細部操作。