Skip to main content
torch.js has not been released yet.
torch.js logotorch.js logotorch.js
PlaygroundContact
Login
Documentation
IntroductionType SafetyTensor ExpressionsTensor IndexingEinsumEinopsAutogradTraining a ModelProfiling & MemoryPyTorch MigrationBest PracticesRuntimesPerformancePyTorch CompatibilityBenchmarksDType Coverage
torch.js· 2026
LegalTerms of UsePrivacy Policy
  1. docs
  2. torch.js
  3. Type Safety

Type-Safe Tensors

The defining feature of torch.js is its ability to track tensor shapes at the type level. This allows TypeScript to catch errors that would normally only surface as runtime crashes in Python.

Type-safety doesn't impose runtime costs

Static vs. Dynamic Shapes

In torch.js, a tensor's type includes its dimensions. We differentiate between Static Shapes (known at compile time) and Dynamic Shapes (known only at runtime).

FeatureStatic ShapeDynamic Shape
TypeTensor<[32, 128]>Tensor<number[]>
ValidationCompile-time (Strict)Runtime-only
IDE FeedbackRed squiggles for errorsGeneric completion
Exampletorch.zeros(2, 3)torch.randn(...dims)

How it Works: Shape Inference

When you call a creation function with literal numbers, torch.js automatically infers the precise tuple type.

import torch from '@torchjsorg/torch.js';

const a = torch.zeros(2, 3); // Inferred as Tensor<[2, 3]>;
const b = torch.randn(1, 10, 5); // Inferred as Tensor<[1, 10, 5]>;

// Operations preserve and transform these types
const c = a.t(); // TypeScript knows this is Tensor<[3, 2]>;
const d = torch.matmul(a, b.at(0)); // TypeScript knows this is Tensor<[2, 5]>;
Visualization of how shape types flow through a neural network

Catching Errors Early

Here are common ML bugs that torch.js prevents before you ever hit "Run".

1. Matrix Multiplication Mismatch

The inner dimensions of two matrices must match ([M, K] @ [K, N]).

const x = torch.zeros(2, 3);
const y = torch.zeros(5, 4);

const z = torch.matmul(x, y);
//        ^^^^^^^^^^^^^^^^^^
// Error: matmul_error_inner_dimensions_do_not_match<3, 5, [2,3], [5,4]>;

2. Invalid Reshaping

The total number of elements must remain constant.

const m = torch.zeros(2, 3); // 6 elements;
const n = m.reshape(4, 4); // 16 elements;
//        ^^^^^^^^^^^^^^^^
// Error: reshape_error_total_elements_mismatch<6, 16>;

3. Slicing Out of Bounds

Accessing an index that doesn't exist.

const t = torch.zeros(5);
const val = t.at(10);
//            ^^^^^
// Error: at_error_index_out_of_bounds<10, 5>;

Branded Error Types: We use a technique called "branding" to ensure that when a shape mismatch occurs, the error message in your IDE specifically names the dimensions that failed, rather than just showing never.

Advanced Usage: Generics

You can write generic functions that work with any shape while still maintaining strict relationships between them.

// A generic linear layer function
function linear<B extends number, I extends number, O extends number>(
  input: Tensor<[B, I]>,
  weights: Tensor<[O, I]>,
  bias: Tensor<[O]>
): Tensor<[B, O]> {
  return input.matmul(weights.t()).add(bias);
}

const input = torch.randn(32, 784); // [32, 784];
const w = torch.randn(128, 784); // [128, 784];
const b = torch.randn(128); // [128];

const output = linear(input, w, b); // TypeScript knows Result is [32, 128];

Pro Tip: If you ever need to "escape" the type system for dynamic data, you can cast to Tensor<any> or Tensor<number[]>, but try to keep your shapes static as long as possible!

Next Steps

  • Einsum - Compile-time parsing of Einstein notation.
  • Einops - Type-safe tensor rearrangements.
  • Tensor Indexing - Slicing with compile-time shape preservation.
Previous
Introduction
Next
Tensor Expressions