This error occurs when TypeScript cannot infer the type of an array, typically when initializing an empty array without type annotations while noImplicitAny is enabled. Fix it by adding explicit type annotations to your array declarations.
This error appears when TypeScript's compiler encounters an array variable that it cannot confidently type, causing it to fall back to the 'any[]' type. This typically happens when you initialize an empty array without providing explicit type information, and your tsconfig.json has the 'noImplicitAny' compiler option enabled (which is true by default in strict mode). The noImplicitAny setting is a safety feature that prevents TypeScript from silently assuming the 'any' type when it cannot infer a more specific type. This is important because 'any' defeats the purpose of TypeScript's type system by allowing any value to be assigned or accessed without type checking. When you create an empty array like 'const items = []', TypeScript initially infers it as an "evolving array type" with type 'any[]'. While TypeScript will update this type as you push elements to it, the noImplicitAny flag catches this implicit typing at declaration time, forcing you to be explicit about what types the array should contain.
The most straightforward solution is to explicitly declare the type of your array when initializing it:
// Before (error)
const items = [];
// After (fixed)
const items: string[] = [];
// or
const items: Array<string> = [];For arrays of objects or complex types:
interface User {
id: number;
name: string;
}
const users: User[] = [];This tells TypeScript exactly what types of elements the array will contain, eliminating the implicit 'any[]' type.
If you can provide initial values, TypeScript will infer the type automatically:
// TypeScript infers string[]
const items = ['initial'];
// TypeScript infers number[]
const numbers = [1, 2, 3];
// TypeScript infers (string | number)[]
const mixed = ['text', 42];This approach works well when you have at least one initial value to provide.
When working with array methods or complex initializations, you can use type assertions:
// Using 'as' assertion
const items = [] as string[];
// Using angle bracket syntax (not recommended in .tsx files)
const items = <string[]>[];
// With Array constructor
const items = new Array<string>();Type assertions are useful when you know the type but TypeScript cannot infer it.
Check if noImplicitAny is enabled in your TypeScript configuration:
{
"compilerOptions": {
"strict": true, // Enables noImplicitAny
"noImplicitAny": true // Explicitly enabled
}
}If you see this error, it means the setting is active. While you could disable it, this is not recommended as it reduces type safety:
{
"compilerOptions": {
"noImplicitAny": false // Not recommended
}
}Keep noImplicitAny enabled and fix the types instead.
When arrays are used in function signatures, ensure proper typing:
// Before (error)
function processItems(items = []) {
// items implicitly has any[]
}
// After (fixed)
function processItems(items: string[] = []) {
// items is explicitly string[]
}
// Or with return type
function getItems(): number[] {
return []; // OK because return type is specified
}Function parameters with default empty arrays need explicit type annotations.
For arrays that shouldn't be modified, use const assertion:
// Creates a readonly tuple type
const items = [] as const; // readonly []
// With initial values
const colors = ['red', 'blue'] as const; // readonly ["red", "blue"]
// Useful for configuration arrays
const CONFIG_VALUES = [1, 2, 3] as const;
type ConfigValue = typeof CONFIG_VALUES[number]; // 1 | 2 | 3This prevents mutations and creates more specific types.
Evolving Array Types: TypeScript has a concept of "evolving array types" where an empty array's type is updated as you push elements to it. However, this only works when noImplicitAny is disabled. With noImplicitAny enabled, you must be explicit upfront.
Design Limitations: According to TypeScript issue #22139, there are known design limitations with noImplicitAny checks on arrays that are mutated. The type checker has architectural constraints that prevent it from fully tracking array mutations in all scenarios.
Never[] vs Any[]: In some contexts, TypeScript may infer an empty array as 'never[]' (an array that cannot contain any elements) rather than 'any[]'. This happens particularly with spread operators, Array constructor, or certain array methods. If you see 'never[]', the solution is the same: add explicit type annotations.
Generic Constraints: When working with generics, you can constrain array types:
function createArray<T extends unknown>(items: T[] = []): T[] {
return items;
}
// Or with default type
function createArray<T = string>(items: T[] = []): T[] {
return items;
}Strict Mode Best Practices: Always keep 'strict' and 'noImplicitAny' enabled in production TypeScript projects. While they require more upfront type annotations, they catch potential runtime errors at compile time and make your codebase more maintainable. The small overhead of adding type annotations pays dividends in code quality and developer experience.
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript