# Type checks and casts (https://docs-fpm2731fy-ton-core-docs.vercel.app/llms/tolk/types/type-checks-and-casts/content.md)



Tolk supports type conversions: either automatic or explicit via the `as` operator.

## Automatic conversions [#automatic-conversions]

Assignable types can be provided explicitly:

```tolk
fun takeOptInt(v: int?) {}

fun main() {
    takeOptInt(100);    // ok, `int` to `int?`
    takeOptInt(null);   // ok, `null` to `int?`
}
```

Certain conversions are automatic:

* `int` to `intN`.
* `AliasForT` and `T` (bidirectional).
* `Cell<T>` to `cell`.

```tolk
fun autocast() {
    var number: int32 = 100;   // auto cast `int` to `int32`
}
```

Non-assignable types cause a compilation error:

```tolk
fun main() {
    var number: int = true;
}
/// file.tolk:2:23: error: can not assign `bool` to variable of type `int`
///            hint: use `as` operator for UNSAFE casting: `<some_expr> as int`
///
///     // in function `main`
///    2 |     var number: int = true;
///      |                       ^^^^
```

## Smart casts [#smart-casts]

Once a variable is checked, the compiler narrows its type. For instance, if a variable [could be `null`](/llms/languages/tolk/types/nullable/content.md) before the check, and the condition is confirmed to be true, the variable's type will not allow `null` in the true block anymore.

```tolk
if (lastCell != null) {
    // here lastCell is `cell`, not `cell?`
}
```

## Operator `is` for union types [#operator-is-for-union-types]

Given a [union type](/llms/languages/tolk/types/unions/content.md) `T1 | T2 | ...`, the `is` operator performs a runtime type test, narrowing the type.

```tolk
fun demo(v: int | Point | cell) {
    if (v is Point) {
        return v.x + v.y;
    }
    // v is `int | cell` here
}
```

## Non-null assertion with operator `!` [#non-null-assertion-with-operator-]

The `!` operator bypasses the compiler's nullability check. It is similar to `!` in TypeScript and `!!` in Kotlin.

```tolk
fun doSmth(c: cell) {}

fun analyzeStorage(nCells: int, lastCell: cell?) {
    // Say, according to the logic of this program,
    // having non-zero number of `nCells` must mean
    // that the `lastCell` is not `null`
    if (nCells != 0) {
        // Therefore, one can explicitly instruct
        // the compiler to recognize that fact
        doSmth(lastCell!);
    }
}
```

## Unsafe cast with operator `as` [#unsafe-cast-with-operator-as]

When non-trivial type transformations are required, the `as` operator overrides the restrictions by performing an unsafe type cast.

For instance, `bool` cannot be assigned directly to `int`. However, a direct cast using the `as` operator is valid since booleans are represented as [TVM](/llms/tvm/overview/content.md) integers: `true` is -1, and `false` is 0.

```tolk
var number: int = true as int; // -1
```

<Callout type="caution">
  The `as` operator skips type checking and performs no validation at runtime — it is purely a compile-time type cast.

  This can lead to sudden errors and hidden bugs. For example, if one cast a slice as `address` and that slice did not hold a valid address, subsequent program becomes undefined and may error whenever that new "address" is used.
</Callout>

Not all transformations are possible. For example, `42 as cell` is invalid. When a cast is inappropriate, the compiler indicates this in diagnostic messages.

The `as` operator converts types that share the same TVM representation:

* `address` is a TVM slice, so `someAddr as slice` is valid.
  * Conversely, `someSlice as address` is valid.
* `bitsN`, where `N` is between 1 and 1023, is a TVM slice, so `someSlice as bitsN` is valid.
* `intN`, where `N` is between 1 and 257, is a TVM integer, so `someInt64 as int32` is valid.
* `bool` is as TVM integer, so `someBool as int` and `someBool as int32` result in -1 or 0.
* Enums are TVM integers, so `someColor as int` is valid.

Finally, the `as` operator cannot be applied to unions: `v as Point` is incorrect. Use the `is` operator and smart casts.
