# `@Type`

### `@Type`

`@Type` builds a type from compile-time type information.

That sounds abstract, so start with the simple version:

```zig
const MyInt = u32;
```

Here, `MyInt` is just another name for the type `u32`.

But `@Type` lets you create a type from a structured description:

```zig
const T = @Type(.{
    .int = .{
        .signedness = .unsigned,
        .bits = 32,
    },
});
```

This creates the type `u32`.

You will not use `@Type` often as a beginner. It is an advanced builtin for generic code, reflection, and metaprogramming. But it is useful to understand what it does, because it completes the pair with `@typeInfo`.

`@typeInfo` breaks a type apart.

`@Type` builds a type from parts.

#### The Pair: `@typeInfo` and `@Type`

Think of the relationship like this:

```zig
const info = @typeInfo(u32);
const T = @Type(info);
```

The first line asks:

```text
What is the structure of u32?
```

The second line asks:

```text
Build a type from this structure.
```

So for many types, this is the rough idea:

```zig
@Type(@typeInfo(T)) == T
```

This means: inspect a type, then rebuild it.

You usually do not write this exact code in normal programs, but it explains the concept.

#### Creating an Integer Type

Here is a small example:

```zig
const std = @import("std");

const U32 = @Type(.{
    .int = .{
        .signedness = .unsigned,
        .bits = 32,
    },
});

pub fn main() void {
    const x: U32 = 123;
    std.debug.print("{}\n", .{x});
}
```

This program creates a 32-bit unsigned integer type.

It is equivalent to using `u32`.

```zig
const U32 = u32;
```

The `@Type` version is longer because it describes the type manually.

#### Signed and Unsigned Integers

You can build signed integer types too:

```zig
const I64 = @Type(.{
    .int = .{
        .signedness = .signed,
        .bits = 64,
    },
});
```

This creates `i64`.

The two important fields are:

```zig
.signedness
.bits
```

The signedness says whether the integer can represent negative numbers.

The bits field says how many bits the integer uses.

#### Why This Exists

At first, `@Type` may look unnecessary. Why write this:

```zig
const U32 = @Type(.{
    .int = .{
        .signedness = .unsigned,
        .bits = 32,
    },
});
```

when you can write this?

```zig
const U32 = u32;
```

For ordinary code, you should write the simple version.

`@Type` becomes useful when the type is computed.

Example: you want to create an unsigned integer type with a bit width chosen at compile time.

```zig
fn UInt(comptime bits: u16) type {
    return @Type(.{
        .int = .{
            .signedness = .unsigned,
            .bits = bits,
        },
    });
}
```

Now you can write:

```zig
const U7 = UInt(7);
const U13 = UInt(13);
const U128 = UInt(128);
```

Zig supports arbitrary-width integer types, so `u7` and `u13` are valid integer types.

#### A Working Example

```zig
const std = @import("std");

fn UInt(comptime bits: u16) type {
    return @Type(.{
        .int = .{
            .signedness = .unsigned,
            .bits = bits,
        },
    });
}

pub fn main() void {
    const U7 = UInt(7);

    const x: U7 = 100;
    std.debug.print("{}\n", .{x});
}
```

A 7-bit unsigned integer can store values from `0` to `127`, so `100` fits.

This would not fit:

```zig
const x: U7 = 200;
```

The compiler rejects it because `200` is too large for 7 bits.

#### `@Type` Returns a Type

This point matters:

```zig
const U7 = UInt(7);
```

`U7` is a type, not a value.

Then you use it as a type:

```zig
const x: U7 = 100;
```

This is the same pattern as:

```zig
const MyNumber = u32;
const x: MyNumber = 100;
```

In Zig, types can be passed around and returned at compile time.

That is one of the main reasons `comptime` is powerful.

#### Creating Array Types

`@Type` can also build array types.

For example:

```zig
const Bytes16 = @Type(.{
    .array = .{
        .len = 16,
        .child = u8,
        .sentinel = null,
    },
});
```

This creates:

```zig
[16]u8
```

You can use it like this:

```zig
const std = @import("std");

const Bytes16 = @Type(.{
    .array = .{
        .len = 16,
        .child = u8,
        .sentinel = null,
    },
});

pub fn main() void {
    const data: Bytes16 = [_]u8{0} ** 16;
    std.debug.print("len = {}\n", .{data.len});
}
```

Output:

```text
len = 16
```

Again, in normal code you should usually write `[16]u8`. But when the length or child type is computed at compile time, `@Type` can be useful.

#### A Generic Array Type Builder

```zig
fn Array(comptime Child: type, comptime len: usize) type {
    return @Type(.{
        .array = .{
            .len = len,
            .child = Child,
            .sentinel = null,
        },
    });
}
```

Use it like this:

```zig
const Buffer = Array(u8, 1024);
```

This creates:

```zig
[1024]u8
```

A complete example:

```zig
const std = @import("std");

fn Array(comptime Child: type, comptime len: usize) type {
    return @Type(.{
        .array = .{
            .len = len,
            .child = Child,
            .sentinel = null,
        },
    });
}

pub fn main() void {
    const Buffer = Array(u8, 8);
    const buf: Buffer = [_]u8{0} ** 8;

    std.debug.print("{}\n", .{buf.len});
}
```

#### Creating Pointer Types

`@Type` can describe pointer types too.

Pointer type descriptions are more detailed because pointers have several properties:

```zig
const PtrToU8 = @Type(.{
    .pointer = .{
        .size = .one,
        .is_const = false,
        .is_volatile = false,
        .alignment = @alignOf(u8),
        .address_space = .generic,
        .child = u8,
        .is_allowzero = false,
        .sentinel = null,
    },
});
```

This creates a type like:

```zig
*u8
```

Do not worry if this feels dense. Pointer types carry a lot of information in Zig. They are not just “addresses.” They also encode constness, alignment, address space, child type, and pointer kind.

For beginner code, write `*u8` directly.

Use `@Type` only when you need to construct such a type programmatically at compile time.

#### `@Type` Is a Metaprogramming Tool

Metaprogramming means writing code that works with code-like structures.

In Zig, types are compile-time values. `@Type` allows you to construct those values.

This is useful for:

generic containers

serialization libraries

binary format readers

compile-time validation

reflection systems

automatic wrappers

low-level APIs that need exact type construction

Most application code does not need `@Type`.

But library code sometimes uses it heavily.

#### Do Not Overuse It

A beginner should not reach for `@Type` first.

Prefer normal type syntax:

```zig
u32
[]const u8
[16]u8
*const Foo
struct { x: i32, y: i32 }
```

Use `@Type` only when the type has to be built from compile-time information.

Clear code is better than clever type construction.

This is clear:

```zig
const Buffer = [1024]u8;
```

This is more complex:

```zig
const Buffer = @Type(.{
    .array = .{
        .len = 1024,
        .child = u8,
        .sentinel = null,
    },
});
```

They describe the same type, but the first version is easier to read.

#### Key Idea

`@Type` creates a type from compile-time type information.

It is the inverse of `@typeInfo`.

Use `@typeInfo` when you want to inspect a type.

Use `@Type` when you want to build a type.

For beginners, the main lesson is simple: Zig treats types as compile-time values, and `@Type` is the builtin that can construct those values explicitly.

