---
id: class-of
title: Types for Class Objects via T.class_of
sidebar_label: T.class_of
---

<!-- TODO(jez) Need to update this with T::Module documentation -->

Classes and modules are also values in Ruby. Sorbet has two ways to describe the type of these class objects: `T.class_of(...)` and `T::Class[...]`.

```ruby
# The type to use in most circumstances:
T.class_of(MyClass)

# Other types that have certain specific use cases
# (discussed below)
T::Class[AnArbitraryType]
T::Module[AnArbitraryType]
```

Prefer `T.class_of(...)` in most cases: it's simpler, usually more precise, and leads to fewer surprises. `T::Class[...]` and `T::Module[...]` are better for some very specific use cases, discussed below. (These specific cases are less common, which is why we recommend using `T.class_of` to those who don't yet know which to pick.)

## What is a `T.class_of` type?

`T.class_of` is used to refer to the type of a class object itself, not values of that class. This difference can be confusing, so here are some examples to make it less confusing:

| This expression... | ...has this type      |
| ------------------ | --------------------- |
| `0`, `1`, `2 + 2`  | `Integer`             |
| `Integer`          | `T.class_of(Integer)` |
| `42.class`         | `T.class_of(Integer)` |

Here's a playground link to confirm these types:

```ruby
# typed: true
T.let(0, Integer)
T.let(1, Integer)
T.let(2 + 2, Integer)

T.let(Integer, T.class_of(Integer))
T.let(42.class, T.class_of(Integer))
```

<a href="https://sorbet.run/#%23%20typed%3A%20true%0AT.let(0%2C%20Integer)%0AT.let(1%2C%20Integer)%0AT.let(2%20%2B%202%2C%20Integer)%0A%0AT.let(Integer%2C%20T.class_of(Integer))%0AT.let(42.class%2C%20T.class_of(Integer))">
  → View on sorbet.run
</a>

## `T.class_of` and inheritance

As with plain [Class Types](class-types.md#inheritance), `T.class_of` types respect inheritance, as long as the argument is a **class** name, not a module name:

```ruby
# typed: true
extend T::Sig

class Grandparent; end
class Parent < Grandparent; end
class Child < Parent; end

sig { params(x: T.class_of(Parent)).void }
def example(x); end

example(Grandparent)   # error
example(Parent)        # ok
example(Child)         # ok
```

<a href="https://sorbet.run/#%23%20typed%3A%20true%0Aextend%20T%3A%3ASig%0A%0Aclass%20Grandparent%3B%20end%0Aclass%20Parent%20%3C%20Grandparent%3B%20end%0Aclass%20Child%20%3C%20Parent%3B%20end%0A%0Asig%20%7Bparams(x%3A%20T.class_of(Parent)).void%7D%0Adef%20example(x)%3B%20end%0A%0Aexample(Grandparent)%20%20%20%23%20error%0Aexample(Parent)%20%20%20%20%20%20%20%20%23%20ok%0Aexample(Child)%20%20%20%20%20%20%20%20%20%23%20ok">
  → View on sorbet.run
</a>

In this example, the `Child` class object passed to the `example` method on the last line has type `T.class_of(Child)`. The `example` takes `T.class_of(Parent)`. When one class inherits another, it's singleton class also inherits the other class's singleton class:

```ruby
# On the class itself, Child < Parent
Child.ancestors
# => [Child, Parent, Grandparent, Object, Kernel, BasicObject]

# On the singleton class, #<Class:Child> < #<Class:Parent>
Child.singleton_class.ancestors
# => [#<Class:Child>, #<Class:Parent>, #<Class:Grandparent>, #<Class:Object>,
      #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
```

Importantly, this only happens for classes, not modules: the singleton class of a module is _never_ the ancestor of some other class. See the next section for more.

## `T.class_of` and modules

Usually when people write `T.class_of(MyInterface)`, what they actually want is either:

- To rewrite the code to use abstract classes instead of interfaces, and then use `T.class_of(MyAbstractClass)`, or
- To use a type like `T.all(T::Class[MyInterface], MyInterface::ClassMethods)`

To showcase why `T.class_of(MyInterface)` is usually a problem and why these two are better solutions, let's walk through an example. The full code for this example is available here:

<a href="https://sorbet.run/#%23%20typed%3A%20true%0Aclass%20Module%3B%20include%20T%3A%3ASig%3B%20end%0A%0Amodule%20MyInterface%0A%20%20extend%20T%3A%3AHelpers%0A%0A%20%20def%20some_instance_method%3B%20end%0A%0A%20%20module%20ClassMethods%0A%20%20%20%20def%20some_class_method%3B%20end%0A%20%20end%0A%20%20mixes_in_class_methods%28ClassMethods%29%0Aend%0A%0Aclass%20MyClass%0A%20%20include%20MyInterface%0Aend%0A%0Asig%20%7Bparams%28x%3A%20T.class_of%28MyClass%29%29.void%7D%0Adef%20example1%28x%29%0A%20%20x.new.some_instance_method%20%20%23%20ok%0A%20%20x.some_class_method%20%20%20%20%20%20%20%20%20%23%20ok%0Aend%0A%0Aexample1%28MyClass%29%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20ok%0A%0Asig%20%7Bparams%28x%3A%20T.class_of%28MyInterface%29%29.void%7D%0Adef%20example2%28x%29%0A%20%20x.new.some_instance_method%20%20%23%20error%3A%20%60new%60%20does%20not%20exist%0A%20%20x.some_class_method%20%20%20%20%20%20%20%20%20%23%20error%3A%20%60some_class_method%60%20does%20not%20exist%0Aend%0A%0Aexample2%28MyClass%29%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20error%3A%20Expected%20%60T.class_of%28MyInterface%29%60%20but%20found%20%60T.class_of%28MyClass%29%60%0A%0Asig%20%7Bparams%28x%3A%20T.all%28T%3A%3AClass%5BMyInterface%5D%2C%20MyInterface%3A%3AClassMethods%29%29.void%7D%0Adef%20example3%28x%29%0A%20%20x.new.some_instance_method%20%20%23%20ok%0A%20%20x.some_class_method%20%20%20%20%20%20%20%20%20%23%20ok%0Aend%0A%0Aexample3%28MyClass%29%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20ok">
  → View on sorbet.run
</a>

Suppose we have some code like this:

```ruby
class MyClass
  def some_instance_method; end
  def self.some_class_method; end
end

sig { params(x: T.class_of(MyClass)).void }
def example1(x)
  x.new.some_instance_method  # ok
  x.some_class_method         # ok
end

example1(MyClass)             # ok
```

`MyClass` declares a class which has an instance method and a class method. The `T.class_of(MyClass)` annotation allows `example1` to call both those methods. None of this is surprising.

Now imagine that we have a lot of these classes and we want to factor out an interface. The straightforward way to factor out an interface that defines both instance and singleton class methods uses [`mixes_in_class_methods`](abstract#interfaces-and-the-included-hook), like this:

```ruby
module MyInterface
  extend T::Helpers

  def some_instance_method; end

  module ClassMethods
    def some_class_method; end
  end
  mixes_in_class_methods(ClassMethods)
end

class MyClass
  include MyInterface
end
```

This will make `some_instance_method` and `some_class_method` available on `MyClass`, just like before. But if we try to replace `T.class_of(MyClass)` with `T.class_of(MyInterface)`, it doesn't work:

```ruby
sig { params(x: T.class_of(MyInterface)).void }  # ← sig has changed
def example2(x)
  x.new.some_instance_method  # error: `new` does not exist
  x.some_class_method         # error: `some_class_method` does not exist
end

example2(MyClass)             # error: Expected `T.class_of(MyInterface)`
                              #        but found `T.class_of(MyClass)`
```

**These errors are correct**. Conceptually, `T.class_of(MyInterface)` represents the type of the `MyInterface` class object _itself_, not "any class object whose instances implement `MyInterface`." We can verify these errors are correct in the repl.

First, we can explain the error on the call to `example2` by looking at ancestors:

```plaintext
❯ MyClass.singleton_class.ancestors
=> [#<Class:MyClass>, MyInterface::ClassMethods,
    #<Class:Object>, T::Private::Methods::MethodHooks, #<Class:BasicObject>,
    Class, Module, T::Sig, Object, Kernel, BasicObject]
```

The first two ancestors of the `MyClass` singleton class are itself and `MyInterface::ClassMethods`. But notably, `#<Class:MyInterface>` **does not** appear in this list, so Sorbet is correct to say that `MyClass` does not have type `T.class_of(MyInterface)`. This is because neither `include` nor `extend` in Ruby will cause `#<Class:MyInterface>` to appear in any ancestors list.

Next, let's explain the other two errors:

```plaintext
❯ MyInterface.singleton_class.ancestors
=> [#<Class:MyInterface>,
    T::Private::MixesInClassMethods, T::Helpers, Module, T::Sig, Object,
    Kernel, BasicObject]
```

For the `MyInterface` singleton class, we see that its only ancestor is itself (ignoring common ancestors like `Object`). Notably, **none** of the classes in this list define either a method called `new` (because `Class` is not there) nor `some_class_method` (because `MyInterface::ClassMethods` is not there).

While these errors are technically correct, we want to be able to type this code. There are two options:

1.  Use an abstract class instead of an interface.

    If this option is available, it's likely the most straightforward. If we change `MyInterface` to `MyAbstractClass`, all our problems vanish. Sometimes this is not possible, because the class in question already has a superclass that can't be changed.

2.  Use `T.all(T::Class[MyInterface], MyInterface::ClassMethods)`.

Specifically, option (2) looks like this:

```ruby
sig { params(x: T.all(T::Class[MyInterface], MyInterface::ClassMethods)).void }
def example3(x)
  x.new.some_instance_method  # ok
  x.some_class_method         # ok
end

example3(MyClass)             # OK
```

We discuss `T::Class` more in the next section. To break down that large type:

- `T.all` is an [Intersection Type](intersection-types.md), which says that `x` has both the type `T::Class[MyInterface]` and `MyInterface::ClassMethods`. It's allowed to call all the methods defined on those types individually.

- `T::Class[MyInterface]` is a type that represents "any class object which, when instantiated, creates instances that at least have type `MyInterface`." Other than that, it says nothing about what singleton class methods the class object has, which means it only assumes those that are defined on `::Class` in the Ruby standard library (basically, just `.new` and `.name`). But Sorbet is smart enough to know that objects created by calling `new` have type `MyInterface`, and thus that `some_instance_method` exists.

- `MyInterface::ClassMethods`

  This module holds all of the interface's class methods, including `some_class_methods`.

## `T::Class` vs `T.class_of`

`T::Class` was designed to model some mismatches between how people think they can use `T.class_of` and how `T.class_of` actually works. `T::Class` is powered by Sorbet's support for [generic classes](generics.md), and is therefore a good choice for writing code that abstracts over class objects.

What are these mismatches? `T.class_of(...)` is, simply, a type representing the singleton class of `A`, matching how singleton classes work in Ruby as closely as possible. However:

- Arbitrary types don't necessarily have singleton classes: for example, `T.class_of(T.noreturn)` is not a valid type, and neither is `T.class_of(T.any(A, B))`.
- As we saw in the previous section, `T.class_of(MyInterface)` **does not mean** "any class object which, when instantiated, creates instances that at least have type `MyInterface`."

Sorbet provides `T::Class` to relax these restrictions. Like other `T::`-prefixed types, this is a [typed wrapper](stdlib-generics.md) for the `::Class` class defined in the Ruby standard library. It's also a [generic class](generics.md), which means it can be given an arbitrary type, unlike `T.class_of(...)` which can only be given a class name, not an arbitrary type). And finally, the generic type parameter on `T::Class` uses the same internal mechanism as Sorbet's [`T.attached_class` type](attached-class.md), which represents "an instance of the current class."

Combined, these features allow `T::Class[...]` to model some common Ruby patterns. For example:

```ruby
sig do
  type_parameters(:Instance)
    .params(klass: T::Class[T.type_parameter(:Instance)])
    .returns(T.type_parameter(:Instance))
end
def instantiate_class(klass)
  instance = klass.new
  puts("Instantiated: #{instance}")
  instance
end

class A; end
class B; end

# converts T.class_of(A) -> A
a = instantiate_class(A)

# converts T.class_of(B) -> B
b = instantiate_class(B)
```

The example above uses [a generic method](generics.md#generic-methods) to take any class object, instantiate it, and understand that the return value's type is the [attached class](attached-class.md) of the class object that was passed in. Calling `instantiate_class(A)` takes a value of type `T.class_of(A)` and produces a value of type `A`. `T::Class[T.type_parameter(:U)]` is a type we can actually write because `T::Class` is a full-fledged generic class. By contrast, we can't write `T.class_of(T.type_parameter(:U))`,because an arbitrary type like `T.type_parameter(:U)` might not have a singleton class.

Another example:

```ruby
module AbstractCommand
  extend T::Helpers
  interface!
  sig { abstract.void }
  def run; end
end

class MyCommand
  include AbstractCommand

  sig { override.void }
  def run; puts("Hello, world!"); end
end

sig { params(command_klass: T::Class[AbstractCommand]).void }
def run_command(command_klass)
  # (1) Instantiate some command class
  command = command_klass.new
  T.reveal_type(command) # => AbstractCommand
  # (2) Run the command
  command.run
end

run_command(MyCommand)
```

In this example, we use `T::Class` to place a constraint on the class object's attached class. The `run_command` method takes class objects, but only those whose attached classes implement the `AbstractCommand` interface. At point (1) we use the class object to instantiate `command_class`, and Sorbet understands that the resulting value has type `AbstractCommand`. This allows point (2) to type check, because Sorbet will know that the `.run` method exists.

### Why have both `T.class_of` and `T::Class`?

There are some things that are only possible to represent with `T.class_of`, and some things that are only possible to represent with `T::Class`.

- `T::Class` is generic in its attached class. It can be applied to an arbitrary type, which means that things like `T::Class[T.any(A, B)]` and `T::Class[MyInterface]` work.

  By contrast, it's simply a syntax error to write `T.class_of(T.any(A, B))` (because this doesn't resolve to a single singleton class), and `T.class_of(MyInterface)` means something different from what people might otherwise expect it to mean.

- `T.class_of` knows what methods are on the singleton class of a class. By contrast, given this:

  ```ruby
  class MyClass
    def self.foo; end
  end
  ```

  The type `T::Class[MyClass]` isn't aware of what singleton class methods exist on that class object, only that the associated instance type is. But `T.class_of(MyClass)` represents both what singleton class methods exist, and also that creating an instance of this class will have type `MyClass`.

So these two types are similar, but each has functionality unique to itself.

The fact that the names are so similar is an unfortunate consequence of history. It might have been better to use syntax like `T.singleton_class(A)` (or maybe even `A.singleton_class`) if we could have anticipated that we would eventually want to build `T::Class` one day.

### `T::Class` vs `Class`

In old versions of Sorbet, the `::Class` class in the Ruby standard library was not generic. In versions of Sorbet that support `T::Class`, `::Class` became generic. Sorbet requires that generic classes in type annotations not be bare--they must be applied to a type argument.

For more information, see [this section in the docs](stdlib-generics.md#generic-class-without-type-arguments).

The difference between `T::Class` and `Class` is the same as the difference between `T::Array` and `Array`. `T::Class` and `Class` represent the same class definition in the standard library, but `T::Class` allows passing type arguments to the generic type parameters defined in `Class`. This error is only reported at [`# typed: strict` or higher](static.md). At lower levels, Sorbet implicitly assumes that a bare type annotation like `Class` is the same as `T::Class[T.anything]`. (See [`T.anything`](anything.md).)

Feel free to replace `Class` with `T::Class[T.anything]` in type annotations where nothing is known about the class object. If there's an obvious more specific type, feel free to narrow `T.anything` to whatever the more specific type is.

### `T.class_of(...)[...]`: Applying type arguments to a singleton class type

For this entire discussion of `T.class_of`, we've been hiding something: Sorbet implicitly treats the singleton classes of classes (not modules) as generic classes. This means that just like how `T::Class[T.type_parameter(:Instance)]` is a valid type, so is `T.class_of(MyClass)[T.type_parameter(:Instance)]`.

Normally, Sorbet hides this fact from users. Whenever it sees something like `T.class_of(MyClass)`, it implicitly assumes the type the user wanted to write was `T.class_of(MyClass)[MyClass]`. This type represents the singleton class of `MyClass`, and makes it clear that the attached class of this singleton class is `MyClass` explicitly.

To further clarify, let's consider this method:

```ruby
class MyClass
  def self.some_singleton_method; end
end

sig do
  type_parameters(:Instance)
    .params(klass: T::Class[T.type_parameter(:Instance)])
    .returns(T.type_parameter(:Instance))
end
def example(klass)
  klass.some_singleton_method
  #     ^^^^^^^^^^^^^^^^^^^^^ error!
  klass.new
end
```

This snippet doesn't work because `T::Class` says "I'll take _any_ singleton class object" but says nothing about what methods might exist on that object.

We can fix this error by using `T.class_of` with an explicit type application:

```ruby
class MyClass
  def self.some_singleton_method; end
end

sig do
  type_parameters(:Instance)
    .params(
      klass: T.class_of(MyClass)[T.all(MyClass, T.type_parameter(:Instance))]
    )
    .returns(T.type_parameter(:Instance))
end
def example(klass)
  klass.some_singleton_method
  #     ^^^^^^^^^^^^^^^^^^^^^ okay!
  klass.new
end
```

This works because the `T.class_of(...)` tells Sorbet what singleton class methods exist, and the `[...]` tells Sorbet what type an object instantiated from that class has.

The `T.all` is an [Intersection Type](intersection-types.md) and is needed because unlike `T::Class`, which allows being applied to any type, the type applied to `T.class_of(MyClass)` must be a subtype of `MyClass`. The intersection is a way to [approximate placing bounds on generic methods](generics.md#placing-bounds-on-generic-methods).

This `T.class_of(...)[...]` syntax generalizes--it can be used to apply types to singleton classes with user-defined `type_template`s as well. Given a class like this:

```ruby
class AnotherClass
  extend T::Generic
  MyTypeTemplate = type_template
end
```

It's possible to apply a type argument to `MyTypeTemplate` with code like

```ruby
T.class_of(AnotherClass)[AnotherClass, Integer]
```

Sorbet still requires that the first argument must be the type for the attached class, and then the remaining arguments apply to each `type_template` the class defines, in turn.

## `T::Module` vs `T::Class`

`T::Module` is just like `T::Class`, but for arbitrary module objects. That is: `T::Module` is a generic wrapper for the `::Module` class defined in the Ruby standard library. Things defined with the `module` keyword are instances of `Module`, just like things defined with the `class` keyword are instances of `Class`. Said another way, in code:

```ruby
class C; end
puts(C.class)           # => Class
T.let(C, T::Class[C])   # => ✅
T.let(C, T::Module[C])  # => ✅

module M; end
puts(M.class)           # => Module
T.let(M, T::Class[M])   # => ⛔️
T.let(M, T::Module[M])  # => ✅
```

Ruby chooses to model these two classes (i.e., the `Class` class and the `Module` class) using inheritance. In Ruby, every `Class` is a `Module`, but not every `Module` is a `Class`. This makes sense, because class objects have all the methods available on module objects (like `mod.name`, `mod.const_get`, etc.), but also have a few methods that are unique to classes (like `klass.new`, i.e., only classes not modules can be instantiated). Said another way, in code:

```ruby
# these are defined in the Ruby standard library:
class ::Module
  def name; end
  def const_get(cnst); end
  # ...
end

class ::Class < ::Module
  def new(...); end
end
```

Just like `T::Class[...]`, `T::Module[...]` can take an arbitrary type, like [`T.type_parameter(:U)`](generics.md#generic-methods) or [`T.any(A, B)`](union-types.md) or [`T.anything`](anything.md) (not just a simple class or module name, like `T.class_of(...)`).

Somewhat counterintuitively, this means that `T::Class[SomeModule]` and `T::Module[SomeClass]` are both valid types:

- `T::Class[SomeModule]` means "any `class` object that has included `SomeModule`"
- `T::Module[SomeClass]` means "any `module` object that inherits from `SomeClass`." It's kind of a weird type, because anything that inherits from `SomeClass` must necessarily also be a `Class`, so this could most likely be replaced with `T::Class[SomeClass]` for free. But explicitly annotating something as `T::Module[...]` prohibits calling any `Class`-specific methods, like `.new`, and maybe this is a guarantee you want to enforce in the type system.

Use `T::Module[...]` over `T::Class[...]` for methods that can accept any module object, and want to be able to operate on the attached class. For example:

```ruby
sig {
  type_parameters(:Attached)
    .params(
      x: T.anything,
      mod: T::Module[T.type_parameter(:Attached)]
    )
    .returns(T.nilable(T.type_parameter(:Attached)))
}
def validate_against_module(x, mod)
  case x
  when mod then x
  else nil
  end
end

data = JSON.parse(File.read('foo.json'))
T.reveal_type(data) # => T.untyped

validated = validate_against_module(data, Enumerable)
T.reveal_type(validated) # => T.nilable(T::Enumerable[T.untyped])

validated = validated&.map {|item| validate_against_module(item, Integer) }
T.reveal_type(validated) # => T.nilable(T::Array[T.nilable(Integer)])
```

This `validate_against_module` method only uses `mod` in a `case` statement, i.e., it only uses the `mod.===(x)`, the [case equality operator]. Accepting `T::Module[...]` instead of `T::Class[...]` allows this method to be maximally permissive, and we see it called with both a module (`Enumerable`) and a class (`Integer`).

[case equality operator]: https://docs.ruby-lang.org/en/master/Module.html#method-i-3D-3D-3D

For further reading:

- Be sure to read all about `T::Class[...]`, because basically everything that is true about how `T::Class[...]` works also holds for `T::Module[...]` from a type system perspective. For example:
  - `T::Module` is to `Module` like `T::Array` is to `Array`: it's a generic wrapper that allows passing type arguments without needing to define a `[]` method
  - `Module` another way of writing `T::Module[T.anything]`. At `# typed: strict` and above, it's an error to have a bare `Module` without specifying an explicit type argument
  - This feature is powered by [generic classes](generics.md) and is related to [T.attached_class](attached-class.md)
- See the [class Class documentation](https://docs.ruby-lang.org/en/master/Class.html) in the official Ruby docs
  - There's a neat ASCII art diagram of the top of the Ruby class hierarchy
- Browse Sorbet's definitions for these two classes: [class.rbi], [module.rbi]
  - defined in Sorbet's [RBI files](rbi.md) for the Ruby standard library

[class.rbi]: https://github.com/sorbet/sorbet/blob/master/rbi/core/class.rbi#L71
[module.rbi]: https://github.com/sorbet/sorbet/blob/master/rbi/core/module.rbi#L26
