Type System | MuleSoft Documentation
# Type System
2.x versions of DataWeave support a type system. To take advantage of the type-checking that the type system executes, you need to provide constraint expressions for variables and functions described in this section. For information about how values for these types are defined, refer to Value Constructs for Types.
A type system defines a set of constraints to a set of constructs, such as:
  * Variables
  * Function parameters


These constraints are used in the type-checking phase, when DataWeave ensures that the values assigned to variables or the arguments for a function call respect its constraints, for example:
DataWeave Script:
```
%dw 2.0
import * from dw::core::Strings
output application/json
var userName: String = "John"
```

The variable definition for `userName` has the constraint of assigning a value of type `String`. If some other value type is assigned, a type-checking error is raised.
DataWeave Script:
```
%dw 2.0
import * from dw::core::Strings
output application/json
fun toUser(id: Number, userName: String): String = "you called the function toUser!"
```

The constraints to call the function `toUser` are that the first argument has to be of type `Number`, the second one of type `String` (to be coercible to those types). Another constraint is that the result of the function has to be of type `String`. This constraint isn’t used in the call for `toUser`; it’s applied to its definition to validate that the function body generates the proper type.
```
toUser(123, "John")
toUser("123", true)
```

Although you might expect the second call to fail, autocoercion enables the call to be successful, and both calls work. In the case of the second function call, there is autocoercion of the `String` value `"123"` to the `Number` value `123`, and the `Boolean` value `true` to the `String` value `"true"`, which makes it possible to call the function. An example of a call that throws a type-checking error is `toUser("a 12", "John")`, because the String value `"a 12"` isn’t coercible to a `Number` type.
DataWeave also uses a global type inference algorithm to validate your code even if no types are specified as constraints.
Although the use of constraints is optional, they can be useful in big scripts or multiple scripts. The type system helps you to avoid bugs in your DataWeave logic because it causes the type-checking algorithm to run. Additionally, when you write your script in an IDE and define these constraints, the tooling helps you to find type checking errors, instead of when the script is running and fails.   
---  
The types supported by the DataWeave type system are divided into three categories:
  * Simple Types
  * Composite Types
  * Complex Types


## Simple Types
Simple types represent values such as strings, Booleans, and so on. These values are atomic; they are not composed of other values. These are the simple types:
  * `Boolean`
  * Temporal: `Date`, `DateTime`, `LocalDateTime`, `LocalTime`, `Time`, `Period`


### Null
`Null` is a type of only one value, the value `null`, which means that `null` cannot be assigned to the type `String` or any other type except for the type `Null`.
For example, the `repeat` function in the String module has the signature `repeat(String, Number): String`, which means that the function accepts as a first parameter only a value of type `String`, and as a second parameter only a value of type `Number.` The function returns a value of type `String`.
DataWeave Script:
```
%dw 2.0
import * from dw::core::Strings
output application/json
---
repeat("a", 3)
```

This returns `"aaa"`, but the following example throws an error because the value `null` cannot be assigned to the parameter that expects a value of type `String`:
DataWeave Script:
```
%dw 2.0
import * from dw::core::Strings
output application/json
---
repeat(null, 3)
```

In the following example, the script assigns to the first parameter a value that is the type `Null` (the type of this value is `Type<Null>`). It returns `"NullNullNull"` because autocoercion coerces the value to the type `String` (`"Null"`).
DataWeave Script:
```
%dw 2.0
import * from dw::core::Strings
output application/json
---
repeat(Null, 3)
```

Some functions have an overloaded signature (the function has multiple definitions for different parameter types) that let you call it with `null`.
For example, the `isNumeric` function from `dw::core::Strings` has the signature `isNumeric(String): Boolean`, which receives a string and successfully returns a result if that string is numeric, but the function is also defined as `isNumeric(Null): Boolean`.
So, if you call the function `isNumeric` with `null` (`isNumeric(null)`), the function does not throw an exception. At runtime, the function that is dispatching algorithm selects the correct function based on the types of the values you use. The function returns `false` because of the definition of `isNumeric` for `null` as the argument.
## Composite Types
A composite type contains other values. The composite types are `Array`, `Object` and `Function`.
### Array Type
An array is of the type `Array<T>` in which `T` is a type parameter that defines the type of the elements inside the array. For example, the syntax to define a variable with the type `Array` of `Number` is:
```
var idsList: Array<Number> = [1, 22, 333, 4444]
```

The variable `idsList` passes the type-checking phase only when the array that is assigned to it only contains values of the `Number` type.
### Object Type
You can define an `Object` type in two ways: `Object` or `{}`. Both define an open object and don’t specify any constraint to their key-value pairs. See also Close and Open Objects.
The syntax for defining an `Object` type with a set of constraints for its key-value pairs is very similar to the syntax for defining the value of an `Object` type:
```
{
  keyName @(attrName: AttrType): valueType,
  ...
}
```

For example, the syntax to define a `User` type with `firstName` `String`, `lastName` `String`, and `age` `Number` is:
DataWeave Script:
```
%dw 2.0
output application/json
type User = {
  firstName: String,
  lastName: String,
  age: Number
}
```

You can apply modifiers to each key-value pair to specify when a field is always present or when a field can be repeated.
For repeated fields use `*`. For example, the following type allows you to have multiple `lastName` fields:
DataWeave Script:
```
%dw 2.0
output application/json
type User = {
  firstName: String,
  lastName*: String,
  age: Number
}
```

For conditional fields, use `?`. For example, the following type allows the `age` field to be present or not:
DataWeave Script:
```
%dw 2.0
output application/json
type User = {
  firstName: String,
  lastName*: String,
  age?: Number
}
```

#### Close and Open Objects
`Object` type can be either closed or open. A _closed_ object accepts an object value only if there are no fields except the key-value pairs specified by the type.
An _open_ object only put constraints on the fields that are declared in the type, and if they are all verified, then the type accepts the value. The type accepts objects that have other fields apart of the ones mentioned in the declaration. All `object` types are open unless specified.
The following example succeeds even if `age` is not in the type declaration because the type of the variable `user` is an open object:
DataWeave Script:
```
%dw 2.0
output application/json
var user: {firstName: String, lastName: String} = {firstName: "John", lastName: "Smith", age: 34}
```

The syntax to specify a closed object is `{| |}`. The following example makes the `User` type support only the keys `firstName` and `lastName`. The script throws an exception because the `age` field is not accepted.
DataWeave Script:
```
%dw 2.0
output application/json
var user: {|firstName: String, lastName: String|} = {firstName: "John", lastName: "Smith", age: 34}
```

### Function Type
DataWeave is a functional language, and functions are considered first class citizens, which means that functions are values with associated types.
The syntax to define a function type is:
```
(paramType: ParamType,...) -> ReturnType
```

For example, if you want to define in a constraint a `Function` type that has a parameter of type `String`, a second parameter of type `Number`, and a `Boolean` return value, the correct syntax is:
```
(paramA: String, paramB: Number) -> Boolean
```
The syntax to specify a closed object is `{| |}`. The following example makes the `User` type support only the keys `firstName` and `lastName`. The script throws an exception because the `age` field is not accepted.
DataWeave Script:
```
%dw 2.0
output application/json
var user: {|firstName: String, lastName: String|} = {firstName: "John", lastName: "Smith", age: 34}
```

### Function Type
DataWeave is a functional language, and functions are considered first class citizens, which means that functions are values with associated types.
The syntax to define a function type is:
```
(paramType: ParamType,...) -> ReturnType
```

For example, if you want to define in a constraint a `Function` type that has a parameter of type `String`, a second parameter of type `Number`, and a `Boolean` return value, the correct syntax is:
```
(paramA: String, paramB: Number) -> Boolean
```

In the following example, you define a function that receives another function as an argument:
DataWeave Script:
```
%dw 2.0
output application/json
fun applyIDsChange(ids: Array<Number>, changeTo: (Number) -> Number): Array<Number> = ???
```

If you call the function `applyIDsChange` with a function that does not match the `changeTo` constraint `(Number) → Number`, DataWeave throws a type-checking error.
For example, the following call works because `abs` is a function that takes a value of the `Number` type and returns a `Number`, which matches the `changeTo` parameter:
```
applyIDsChange([1,-6, 3, -8], abs)
```

But the following call fails because `sum` is a function that takes an `Array` and returns a `Number`, so it does not match the parameter constraint:
```
applyIDsChange([1,-6, 3, -8], sum)
```

## Complex Types
Complex types include the `Any` and `Nothing` types, the `Union` type, the `Intersection` type, and `Literal` types, each of which is named intuitively.
### Any and Nothing
In some cases, you cannot enforce a restriction because the type accepts all the value:
  * `Any` type accepts all possible values.
  * `Nothing` type accepts no value, but it can be assigned to all the types. This type is not frequently used explicitly, but it is used by the type inference algorithm.


### Union Type
The `Union` type is used to compose types. The syntax to define a `Union` type is:
```
TypeA | TypeB | ...
```

The following example defines a variable with a constraint that accepts a value of type `String` or `Number`:
```
var age: String | Number = if (payload.allStrings) "32" else 32
```

A common pattern is to use `Null` type with a `Union` type to specify that a type accepts `null` as a value. In the following example, the function `parseEmail` allows inputs of type `String` or `Null`. In this case, you can have a object with a payload optional field `email` and you call the function with `payload.email`.
```
fun parseEmail(email: String | Null) = "Code that handles email being of type String or Null"
```

### Intersection Type
_Introduced in DataWeave 2.3.0. Supported by Mule 4.3 and later._
The `Intersection` type intersects `Object` types. In this case, the intersection works as the concatenation (`++`) of object types.
The syntax for the `Intersection` type is:
```
TypeA & TypeB & ...
```

In the following example, the `Intersection` concatenates the two `Object` types, resulting in the type `{name: String, lastName: String}`. The type is an open object that can accept additional key-value pairs. The variable accepts the value assigned to it:
```
var a: {name: String} & {lastName: String} = {name: "John", lastName: "Smith", age: 34}
```

In the case of closed objects, it returns the concatenation of the object types but results in a closed object. In the following example, the intersection results in the type `{|name: String, lastName: String|}`, which throws an exception because a closed object does not accept an `Object` value if there are additional fields in the object (field `age`):
```
var a: {|name: String|} & {|lastName: String|} = {name: "John", lastName: "Smith", age: 34}
```

### Literal Types
_Introduced in DataWeave 2.3.0. Supported by Mule 4.3 and later._
A literal type represents exactly one value. For example, the `String` value `"foo"` can be represented with the type `"foo"`.
The following literal types are included to the type system:
  * `String` literal types
  * `Number` literal types
  * `Boolean` literal types


You can use literal types with `Union` types to declare a type as a finite set of allowed values. For example, the following type declarations are aliases of `Union` and literal types:
```
type Weekdays = "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday"
type Days = Weekdays | "Saturday" | "Sunday"
```

In the following example, the variable accepts only a value of the literal types `404` and `500`. The type system ensures before runtime that the variable can be only one of those literal values:
DataWeave Script:
```
%dw 2.0
output application/json
var errorStatusCode: 404 | 500 = payload.statusCode match {
  case "error 404" -> 404
  case "error 500" -> 500
}
```

Function overloading enables you to define different behaviors based on the input argument’s value:
DataWeave Script:
```
%dw 2.0
import * from dw::core::Strings
output application/json
fun errorHandling(errorCode: 404 | 405, response): String = "Code for error 4XX handling here!"
fun errorHandling(errorCode: 500 | 501, response): String = "Code for error 5XX handling here!"
---
errorHandling(payload.statusCode, payload)
```

At runtime, the function-dispatching algorithm selects the correct function based on the type of the value of `payload.statusCode`. It is not necessary to check the value of an argument with an `if` statement to change the behavior of the function.
### Type Parameters
A type parameter enables you to write a function or data type generically so that you can handle values identically, without depending on the type of the values.
For example, you can define a function that returns the first element of an array without losing its type information. In the example, the variable definitions `firstString:String` and `firstNumber:Number` specify the type of the item in the array that the `head` function takes as input.
```
%dw 2.0
fun head<ItemType>(elements: Array<ItemType>): ItemType = elements[0]!
var firstString:String = head(["DataWeave", "Java", "Scala", "Haskell"]) ++ " Rules!!!"
var firstNumber:Number = head([1,2,3])
output application/json
---
firstNumber
```

In the body of the script, `firstNumber` returns the number `1`. If you replace `firstNumber` with `firstString`, the script returns the string `"DataWeave Rules!!!"`.
#### Binding Type Parameters
You can bind type parameters to require a value of a specific type. Appending `{name: "DataWeave"}` in the following example is valid because `{name: String}` in the function definition indicates that the value of the `name` key must be a string.
```
%dw 2.0
fun addName<User <: {} >(user: User): User & {name: String} = user ++ {name: "DataWeave"}
var myUser: {name: String, developers: Number} = addName({developers: 3})
```

#### Parameterizing Type Definitions
You can use type parameters to parameterize type definitions. For example, assume that you define a data structure that models file content, one for text files and the other for binary files. You can use type parameters to construct new types that dispatch the correct implementation.
```
%dw 2.0
type FileData<Content> = {
  data: Content,
  name: String
}
fun read(file: FileData<String>) = "This is a text file with data " ++ file.data
fun read(file: FileData<Binary>) = "This is a binary file with data " ++ (file.data as String {base: "64"})
---
{
 binary: read({data: "Hello World" as Binary, name: "myFile.bin"}),
 text: read({data: "Hello World", name: "myFile.txt"})
}
```
#### Parameterizing Type Definitions
You can use type parameters to parameterize type definitions. For example, assume that you define a data structure that models file content, one for text files and the other for binary files. You can use type parameters to construct new types that dispatch the correct implementation.
```
%dw 2.0
type FileData<Content> = {
  data: Content,
  name: String
}
fun read(file: FileData<String>) = "This is a text file with data " ++ file.data
fun read(file: FileData<Binary>) = "This is a binary file with data " ++ (file.data as String {base: "64"})
---
{
 binary: read({data: "Hello World" as Binary, name: "myFile.bin"}),
 text: read({data: "Hello World", name: "myFile.txt"})
}
```

## Reuse Types
You can declare and use types within the same DataWeave script (see Type System), or you can reuse types from different sources by loading them with a specific module loader. DataWeave currently supports loading types from:
  * Reusing Types from DataWeave Modules
  * Reusing Types from a JSON Schema
  * Reusing an XML Schema
  * Reusing Types from Java Classes
  * Reusing Types from an Avro Schema


Module loaders are used to load files as DataWeave modules, in which different parts of those files are loaded as DataWeave functions, variables, types, and namespace definitions. Using a prefix such as `java!` or `xmlschema!` in the import directive tells DataWeave which module loader to use when loading the Java class or the XML schema as a DataWeave module.