Importing types
Useimport type for type-only imports to ensure they are erased at compile time:
The DType type
DType is a string union representing all supported data types:
NDArray vs NDArrayCore
The two array types correspond to the two main entry points:NDArray extends NDArrayCore, so every NDArray satisfies the NDArrayCore type. Both types expose the same properties: shape, ndim, size, dtype, data, strides, flags, base, itemsize, nbytes.
Writing generic functions
Accept NDArrayCore for maximum compatibility
If your function only uses standalone functions (not method chaining), acceptNDArrayCore. This lets callers pass either type:
Accept NDArray when you need methods
If your function uses method chaining, requireNDArray:
Pattern for library authors
If you are publishing a library that depends on numpy-ts, acceptNDArrayCore in your public API and return NDArrayCore. This gives your users the choice of which entry point to use.
Type narrowing with dtype
Thedtype property is typed as the array’s dtype parameter D (which is DType for an unparameterized NDArray). When you branch on the dtype of an unparameterized array, switch narrows it directly:
isIntegerDType, isFloatDType, and isComplexDType:
Shape inference
Array shapes are exposed asreadonly number[]. You can use this to write shape-aware utilities:
Combining with generics
For functions that work with multiple array types, use TypeScript generics:Since
NDArray extends NDArrayCore, a generic bounded by NDArrayCore accepts both types. The return type preserves the caller’s type through the generic parameter.Type-safe creation functions
Creation functions take the dtype as a positional argument, and the dtype literal flows into the return type (see Compile-time dtype tracking below):Compile-time dtype tracking
NDArray<D> is parameterized by its dtype. When you create an array with a dtype literal, that literal is carried through the type system so operations report their exact result dtype — following the same NumPy promotion rules enforced at runtime.
Element access returns the right scalar type
get, iget, and item return bigint for int64/uint64, a Complex for complex dtypes, and number otherwise.
Result dtypes are tracked per operation
Each operation reports the dtype NumPy would produce:The promotion type helpers
The promotion rules are exposed as type-level helpers you can use directly, generated from the same single source of truth as the runtime rules:Caveats
- Scalar operands keep the array’s dtype.
intArr.add(2.5)is typedNDArray<'int32'>, not float. TypeScript sees only the typenumber, never the value, so it cannot distinguish an integer literal from a float — modelling NumPy’s weak-scalar promotion is not possible. Use an explicitastypewhen you need the widened result. - Runtime-computed dtypes widen to
DType. When a dtype is chosen at runtime (array(data)without a literal, or aDType-typed variable), the result isNDArray<DType>— correct, just not narrowed. - A few operations stay
NDArray<DType>on purpose — their result dtype can’t be known from the types. This is honest widening, not a gap: multi-array joins (concatenate,stack,hstack, …) andchoose/select, whoseNDArray[]inputs have already erased the per-array dtype; data/file/callback sources (array(data),fromfile,apply_along_axis); and a few data-dependent functions (poly,roots, whose output is real or complex depending on the values). - Index results diverge from NumPy. NumPy returns
int64/intpfor index-producing ops; numpy-ts returnsnumber-yielding dtypes instead, so element access staysnumberrather thanbigint(int64 is BigInt-backed here). Concretely:argmin/argmax/nanargmin/nanargmax→int32, andargsort/argpartition/argwhere/flatnonzero/nonzero→float64. Both the types and the runtime agree on this. Caveat: theint32arg-reductions overflow above ~2.1 billion (2³¹) elements along the reduced axis; thefloat64family is safe to 2⁵³. A unified 53-bit index dtype (intp) is planned to remove this split — see the roadmap. float16is float32-backed without native support. The type↔runtime dtype match holds everywhere exceptfloat16on engines lacking a nativeFloat16Array(older runtimes). There, afloat16result is stored in aFloat32Array, so its runtime.dtypereads'float32'while the compile-time type stays'float16'. Scalar/element types are unaffected.