# Mold

## TypeScript

Mold的出現主要是因為JavaScript沒有Interface、Type等Struct的功能，這在運行過程時容易遇到非預期的錯誤。

TypeScript是一個解決方案，以下是使用時呈現的方式：

```javascript
// Basic function
function sum(v1: number, v2: number): number {
    return v1 + v2
}

// Interface based
interface Person {
    firstName: string
    lastName: string
}

function greeter(person: Person) {
    return "Hello, " + person.firstName + " " + person.lastName
}
```

{% hint style="info" %}
TypeScript的限制在編譯後就失去了功能，意味著今天在與客戶端交流時仍難以避免資料型態的意外。
{% endhint %}

## How To Use

Mold不能被外部所引用，最直接的使用方法是宣告在Tool的Request內。

```javascript
const tools = {
    demo: {
        request: ['string', 'number'],
        handler: self => self.success()
    }
}
```

在執行時能便會附加檢查功能：

```javascript
packhouse.tool('group/demo').action('123', '456', error => {
    console.log(error.message) // Parameter 1 not a number(456).
})
```

### Expression

Mold可以藉由`|`符號加入參數，協助開發者應付特殊狀況。

```javascript
const tools = {
    demo: {
        request: ['number|min:50'],
        handler: self => self.success()
    }
}
```

### Casting

能夠使用`self.casting`在[Handler](/the-instance/group/tool.md#handler)中做轉換。

```javascript
const tools = {
    demo: {
        handler(self, value) {
            try {
                let newValue = self.casting('number|min:50', value)
                self.success(newValue)
            } catch(e) {
                self.error(e)
            }
        }
    }
}
```

### Null

在Request中宣告`null`可以忽略驗證欄位。

```javascript
const tools = {
    demo: {
        request: [null, 'number'],
        handler: self => self.success()
    }
}
```

### Optional

在名稱後加入`?`符號可以使該參數為`null`或`undefined`的時候忽略驗證。

```javascript
const tools = {
    demo: {
        request: ['number?|min:50'],
        handler: self => self.success()
    }
}
```

## Custom Define Mold

Mold可以同時具有檢查與轉換的功能，呈現的方式如下：

{% hint style="info" %}
Mold不允許非同步運算。
{% endhint %}

```javascript
const molds = {
    int(value) {
        if (typeof value === 'number') {
            return Math.floor(value)
        } else {
            throw new Error('Value not a number.')
        }
    }
}
```

第二個參數為`context`，能夠做更進階的應用：

```javascript
const molds = {
    int(value, { index, utils, extras }) {
        if (extras.positive === true && value >= 0) {
            throw new Error(`Params ${index} must positive.`)
        }
        if (extras.min && Number(extras.min) > value) {
            throw new Error(`Params ${index} less than ${extras.min}.`)
        }
        if (typeof value === 'number') {
            return Math.floor(value)
        } else {
            throw new Error(`Params ${index} not a number.`)
        }
    }
}

const tool = {
    demo: {
        request: ['int|min:50|positive'],
        handler: (self, value) => self.success(value)
    }
}
```

## Verify Expression

基於[`utils.verify`](/the-instance/utils.md#verify)的格式，有更好的結構表達與文件生產。

```javascript
const molds = {
    person: {
        firstName: [true, ['string']],
        lastName: [true, ['string']]
    }
}

const tools = {
    demo: {
        request: ['person'],
        handler: (self, person) => self.success()
    }
}

let person: {
    firstName: 'green',
    lastName: null
}

// ... 省略註冊行為

packhouse.tool('group/demo').action(person, error => {
    // Parameter 0 verification error, Key(lastName) is required.
    console.log(error)
})
```

## Core Molds

不是每個Mold都要重新定義，系統本身提供了許多常用的型態：

#### type

使用[`utils.getType`](/the-instance/utils.md#gettype)作驗證。

* { string } is - 目標type，一定需要該參數

```javascript
['type|is:string']
```

#### number

參數必須為數字。

* **min** - 數字必須高於指定數字
* **max** - 數字必須低於指定數字
* **int** - 數字轉換成整數

```javascript
['number|min:0|max:50|int']
```

#### boolean

參數必須為`true`或`false`。

#### string

參數必須為字串。

* **is** - 指定字串內容，可以用`,`分割多個對象。

```javascript
['string|is: red, green, blue']
```

#### array

參數必須為陣列。

#### buffer

參數必須為`Buffer`。

#### object

參數必須為`Object`。

#### function

參數必須為`Function`。

#### date

參數必須為`new Date`支援的時間格式。

#### required

參數為必填。

> 如果你這樣寫required?，會無效。

## Create Self Core Mold

開發人員可以自定義系統Mold，這樣就能夠在所有場合使用自定義Mold。

{% hint style="info" %}
我們不建議個別自定義系統Mold，若有需要請參考[Merger](/the-instance/merger.md)章節來管理Mold。
{% endhint %}

{% hint style="info" %}
當系統Mold與Group Mold有相同名稱時，Group Mold優先。
{% endhint %}

```javascript
let packhouse = new Packhouse()
packhouse.addMold('int', value => parseInt(value))

const tools = {
    demo: {
        request: ['int'],
        handler: self => self.success()
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://packhouse-doc.metalsheep.com/the-instance/group/mold.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
