Jose Antonio
Jose Antonio

Reputation: 444

Conditional generic types in typescript

Imagine you have a Foo interface that receives a generic type T like

interface Foo<T> {
  ...
  bar: T;
}

now you want the T type to be optional, so you set an default value

interface Foo<T = undefined> {
  ...
  bar: T;
}

but 'bar' is still required.

How do I get 'bar' to be required (not undefined) when type T is set, and remove it (or set it as not required) when Type T is not set?

I've tried something like the lines bellow, but 'bar' is still required. I could add a question mark to the 'bar' property but then 'bar' will not be required when T is set.

interface Foo<T = undefined> {
  ...
  bar: T extends undefined ? never : T;
}

Any idea if this is even possible?

Upvotes: 1

Views: 436

Answers (3)

Todd Skelton
Todd Skelton

Reputation: 7239

This should work

type Foo<T = undefined> = T extends undefined ? {} : {
   bar: T
}

const foo : Foo = { bar: "hello" }
const bar: Foo<string> = { bar: "hello" }
const foobar : Foo = {}

Upvotes: 3

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249466

Depends why you need this, the base and derived interface solution is pretty good for most situations (presented in another answer here).

You can't use a conditional type to make a field optional. But you can use an intersection type instead:

type Foo<T = undefined> = {
  otherFields: string
} & ([T] extends [undefined] ? {} : {
  bar: T
})

let x: Foo<undefined> = {
  otherFields: ""
}

let x2: Foo<string> = {
  otherFields: "",
  bar: ""
}

Playground Link

Upvotes: 2

Ackdari
Ackdari

Reputation: 3498

You can model it with two interfaces

interface FooBase {
  // all expext bar 
}

interface Foo<T> extends FooBase {
  bar: T
}

this way the interface FooBase contains every thing that that is always requiered and Foo only conatins bar but also enforces every thing that is declared by FooBase.

Upvotes: 1

Related Questions