# Overview

So far, we have worked only with the low-level untyped version of validator functions which use the `BuiltinData` type for its arguments. With typed validators, we can define our own types for validation arguments, simplifying things. These types still get compiled down to the low-level `BuiltinData` type, but our high-level code can be more understandable.

For typed validators, we will use the `mkTypedValidator` instead of the `mkValidatorScript` that we have been using so far. `mkTypedValidator` uses the `ToData` typeclass (<https://intersectMBO.github.io/plutus-apps/main/plutus-ledger-api/html/Plutus-V2-Ledger-Api.html#t:ToData>) to convert the given types to `BuiltinData` types. In Haddock, we can find that the instances for this typeclass are already defined for regular Haskell and Plutus types. In the case of using those basic types, we just need to create a new data type and make it an instance of the `ValidatorTypes` class (<https://intersectMBO.github.io/plutus-apps/main/plutus-ledger/html/Ledger-Typed-Scripts.html#t:ValidatorTypes>). The basic syntax for creating a validator type is as follows:

```haskell
data ArbitraryValidatorTypeName

instance Scripts.ValidatorTypes ArbitraryValidatorTypeName where
  type instance DatumType ArbitraryValidatorTypeName = Slot       -- Datum type (basic Plutus)
  type instance RedeemerType ArbitraryValidatorTypeName = Integer -- Redeemer type (basic Haskell)
```

With a typed validator, we use our defined types for `Datum` and `Redeemer` instead of the `BuiltinData` so the type signature of the `mkValidator` changes. Besides using our defined types for `Datum` and `Redeemer`, it also now returns a `Bool` instead of a `()`, with `True` signifying successful validation and `False` signifying a failed one.

```haskell
mkValidator :: Slot -> Integer -> Plutus.ScriptContext -> Bool
mkValidator = ...
```

Following that, we can create a ***typed*** validator with the validator we defined above using the `Plutus.Script.Utils` package:

```haskell
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
...

import qualified Plutus.Script.Utils.Typed as PSU
import qualified Plutus.Script.Utils.V2.Typed.Scripts as PSU.V2

typedValidator :: PSU.TypedValidator ArbitraryValidatorTypeName
typedValidator = PSU.V2.mkTypedValidator @ArbitraryValidatorTypeName
    $$(PlutusTx.compile [|| mkValidator ||])
    $$(PlutusTx.compile [|| wrap ||])
    where
        wrap = PSU.mkUntypedValidator
```

`PSU.TypedValidator` is version agnostic, but we must use `PSU.V2.mkTypedValidator` if we want to compile to Plutus V2. We also need the `{-# LANGUAGE TypeApplications #-}` and `{-# LANGUAGE TypeFamilies #-}` extensions for the above syntax to work properly.

### Creating Custom Data Types

If we want to create custom data types for our datum or redeemer, we must also create them as instances of the aforementioned `ToData` typeclass. We should simply use the [`PlutusTx.unstableMakeIsData`](https://intersectMBO.github.io/plutus-apps/main/plutus-tx/html/PlutusTx.html#v:unstableMakeIsData) on our defined datum/redeemer type. The difference between `unstableMakeIsData` and `makeIsDataIndexed` is that the latter ensures consistent indexing that is required to be specified and it is **recommended to use `makeIsDataIndexed` in production** because it ensures the same data structure results across different Plutus versions.

```haskell
data ExampleDatum = ExampleDatumConstr {
    field1 :: Field1Type,
    field2 :: Field2Type
  }
PlutusTx.unstableMakeIsData ''ExampleDatum
```

The rest is the same, we just use our data type for the datum/redeemer types:

```haskell
data ArbitraryValidatorTypeName

instance Scripts.ValidatorTypes ArbitraryValidatorTypeName where
  type instance DatumType ArbitraryValidatorTypeName = ExampleDatum -- Datum type (custom defined)
  type instance RedeemerType ArbitraryValidatorTypeName = Integer   -- Redeemer type (basic Haskell)
```


---

# 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://plutus.hpmeducation.com/typed-validators/overview.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.
