TS2314Semantic Error
Since TS 1.0

Fix TS2314: Generic Type Requires Type Arguments

Learn why TypeScript throws TS2314 when a generic type is used without its type arguments, and how to fix bare Array, Promise and Record annotations.

error TS2314: Generic type 'X' requires N type argument(s)

What This Error Means

TS2314 means you referenced a generic type — an interface, class or type alias declared with type parameters — but left the type-argument list off. Array instead of Array<string>, ApiResponse instead of ApiResponse<UserProfile>. The declaration needs to know what it is generic over, you did not say, and the compiler will not guess.

The check is purely structural and runs in the core checker: no strict setting, no flag, no configuration turns it on or off. Every type parameter that has no default is a required argument, so TypeScript counts the parameters it found in the declaration, counts the arguments you supplied, and reports the difference. That count is the most useful part of the message — it tells you how many types the declaration wants before you go and look it up.

let orderIds: Array = []
              ~~~~~
error TS2314: Generic type 'Array<T>' requires 1 type argument(s).

Note the shape of the name in the message. For interfaces and classes TypeScript prints the declared parameter names — 'Array<T>', 'Map<K, V>' — which is a free hint about what each slot means. For type aliases it prints the bare name instead ('Record'), so you get the count but not the labels.

One point of confusion worth clearing up straight away: this error only fires in type positions. Array.isArray(value) is a value, not a type, and it compiles fine on its own. It is the annotation let rows: Array that fails.

Common Causes

1. A Built-In Generic Used Bare

Array, Promise, Map, Set and Record are all generic, and none of them has a default type parameter. This is the form most people hit first, usually by writing the type the way you would in Java or C#.

// ❌ Broken
interface Order { id: string; total: number }
 
let orderIds: Array = []
//            ~~~~~ Error: Generic type 'Array<T>' requires 1 type argument(s). (TS2314)
let pendingSync: Promise
//               ~~~~~~~ Error: Generic type 'Promise<T>' requires 1 type argument(s). (TS2314)
let ordersById: Record<string>
//              ~~~~~~~~~~~~~~ Error: Generic type 'Record' requires 2 type argument(s). (TS2314)
// ✅ Fixed — every generic gets the arguments its declaration asks for
interface Order { id: string; total: number }
 
let orderIds: Array<string> = []
let pendingSync: Promise<void> = Promise.resolve()
let ordersById: Record<string, Order> = {}

A bare Array is not shorthand for any[], which is the assumption behind most of these. Record<string> is the giveaway for the other half: Record takes a key type and a value type, and supplying one of two is still an error. For arrays, string[] and Array<string> mean exactly the same thing — use whichever reads better in the surrounding code.

2. Your Own Generic Used Without Arguments

The second common source is a type you own that became generic. A response wrapper starts out concrete, someone parameterises the payload, and every call site that annotated it by name now fails.

// ❌ Broken — ApiResponse gained a type parameter, this annotation did not
interface UserProfile { id: string; email: string }
 
interface ApiResponse<T> {
  data: T
  status: number
  receivedAt: Date
}
 
export function renderProfile(response: ApiResponse): string {
  //                                    ~~~~~~~~~~~
  // Error: Generic type 'ApiResponse<T>' requires 1 type argument(s). (TS2314)
  return response.data.email
}
// ✅ Fixed — name the payload at the call site
export function renderProfile(response: ApiResponse<UserProfile>): string {
  return response.data.email
}

If most callers do not care about the payload, the better fix is on the declaration rather than at every use. A default type parameter makes the argument optional:

// ✅ Also fixed — a default turns the argument into an optional one
interface ApiResponse<T = unknown> {
  data: T
  status: number
  receivedAt: Date
}
 
export function logStatus(response: ApiResponse): number {
  return response.status
}

Reach for unknown rather than any as the default. Both silence TS2314, but unknown keeps the compiler asking for a check before you read response.data, while any quietly switches type checking off for everything downstream of that property.

3. A Library Major That Added a Required Type Parameter

This is the version of TS2314 that appears without you touching the line. A dependency upgrade turns a concrete exported type into a generic one — react-select 5 made ControlProps take Option, IsMulti and Group; Angular 2 did it to Type; old @types/react did it to Component. Your annotation was valid last week.

// ❌ Broken — react-select 5.x typings, ControlProps is now generic
import type { ControlProps } from 'react-select'
 
export interface CurrencyOption {
  value: string
  label: string
}
 
export function controlClassName(props: ControlProps): string {
  //                                    ~~~~~~~~~~~~
  // Error: Generic type 'ControlProps<Option, IsMulti, Group>' requires 3 type argument(s). (TS2314)
  return props.isFocused ? 'select-control is-focused' : 'select-control'
}
// ✅ Fixed — fill in the slots the new declaration expects
import type { ControlProps, GroupBase } from 'react-select'
 
export function controlClassName(
  props: ControlProps<CurrencyOption, false, GroupBase<CurrencyOption>>,
): string {
  return props.isFocused ? 'select-control is-focused' : 'select-control'
}

The parameter names in the message are your documentation here: Option is the shape of one item, IsMulti is a boolean literal saying whether the select is multi-value, Group is the grouping wrapper. Later releases of react-select added a default for Group, which is why the same code on a newer version reports TS2707 (requires between 2 and 3 type arguments) instead. Check the library's migration notes before you invent arguments; pinning the previous @types version is a stopgap for a red CI run, not a fix.

4. extends or implements Without the Arguments

A heritage clause is a type position too. Extending a generic base class or implementing a generic interface without arguments fails the same way — and the follow-up errors it triggers inside the subclass body often hide the real one.

// ❌ Broken — the base class is generic, the extends clause is not
interface Order { id: string; total: number }
 
abstract class Repository<TEntity> {
  protected items: TEntity[] = []
 
  add(entity: TEntity): void {
    this.items.push(entity)
  }
}
 
class OrderRepository extends Repository {
  //                          ~~~~~~~~~~
  // Error: Generic type 'Repository<TEntity>' requires 1 type argument(s). (TS2314)
  readonly label = 'orders'
}
// ✅ Fixed — the subclass says which entity it stores
class OrderRepository extends Repository<Order> {
  totalRevenue(): number {
    return this.items.reduce((sum, order) => sum + order.total, 0)
  }
}

implements behaves identically: class OrderCache implements EntityCache on an EntityCache<TValue> reports the same error, and the members you were asked to implement go unchecked until you fix it. If a subclass should stay generic rather than commit to one entity, forward the parameter instead of filling it in — class AuditedRepository<TEntity> extends Repository<TEntity> is a valid argument list, because a type parameter in scope is a perfectly good type argument.

How to Fix It

  1. Read the count in the message and supply that many arguments. requires 1 type argument(s) means one, requires 2 means two, and the printed name usually spells out what each slot is for — 'Map<K, V>' is a key and a value. This is the fix for the overwhelming majority of TS2314s, and it takes one edit.

  2. Go to the declaration when the slots are not obvious. Hover the type or jump to its definition and read the parameter list with its constraints. A parameter constrained as IsMulti extends boolean wants true or false, not boolean's runtime cousin; one constrained extends keyof T wants a key. Passing something the constraint rejects is the next error along, TS2344.

  3. Add a default type parameter if you own the generic and most callers agree. interface ApiResponse<T = unknown> makes the argument optional without loosening anything for the callers who do pass one. Defaults must follow all required parameters, and once only some parameters have defaults the diagnostic becomes TS2707 with a range instead of a count.

  4. Use unknown when the argument genuinely is not known yet, never any. Promise<unknown> and ApiResponse<unknown> both compile and both keep the value opaque until you narrow it. any also compiles, and takes the rest of the type checking in that expression with it. Casting the annotation away with as any or silencing the line with @ts-ignore hides a missing type argument that will resurface as a runtime bug.

  5. Treat a TS2314 that appears after an upgrade as a migration task. If you did not edit the line, a dependency changed its exported type. Read the release notes, apply the arguments the new declaration wants, and keep @types packages on majors that match their runtime package. Fixing it properly also keeps future upgrades from landing on the same annotation twice.

FAQ

What causes TypeScript error TS2314?

TS2314 fires when a generic type is named in a type position without the type arguments it requires. The compiler resolved the name — the type exists, and it is generic — but the argument list is missing or short, and none of the unfilled parameters has a default. It happens with built-ins (Array, Promise, Record), with your own types after someone parameterises them, and with library types whose new major added a parameter. The count in the message comes straight from the declaration, so it always tells you exactly how many arguments the fix needs.

How do I fix Generic type 'Array<T>' requires 1 type argument(s)?

Say what the array holds:

let orderIds: Array<string> = []
let orderIds2: string[] = []

Both lines mean the same thing. What does not work is leaving the argument off and hoping for any[] — TypeScript has no implicit fallback for a missing type argument, so a bare Array is an error rather than a loose annotation. If the element type really is open-ended at that point in the code, Array<unknown> is the honest version and keeps the compiler asking for a narrowing check before you use an element. The same rule covers the other built-ins: Promise<void> takes one argument, Map<string, Order> and Record<string, number> take two.

Can I make a type parameter optional to avoid TS2314?

Yes — give it a default, and callers may omit it:

interface PagedResult<TItem, TCursor = string> {
  items: TItem[]
  cursor: TCursor
}
 
type OrderPage = PagedResult<Order>

Two rules apply. Defaults have to come after every required parameter, the same way optional function parameters do. And once a type has both required and defaulted parameters, omitting everything no longer reports TS2314 — you get TS2707 instead, which names a range: Generic type 'PagedResult<TItem, TCursor>' requires between 1 and 2 type arguments. That change of error code is a useful signal in itself. TS2314 means every parameter is required; TS2707 means some of them already have defaults and you are still short. Defaults arrived in TypeScript 2.3, so a library that relies on them will still report TS2314 on an older compiler.

Related Errors

Practice This

Put your understanding to the test with these related challenges.

Or browse all TypeScript practice challenges to keep sharpening your type-level skills.

Related Concepts

Share this reference

Become a TypeScript Pro

Track your progress through 100+ hands-on challenges. Free, sign in with GitHub.

Or start solving right away: explore all TypeScript challenges