Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optional property based on whether the generic type is passed

How to make an interface so that when T is passed, a is typed T, and when it's not passed, a can be optional (a missing property), for instance:

interface A<T = void> {
  a: T
}

const a1: A<string> = { a: 'a' } // ๐Ÿ‘ˆ No error, good

const a2: A = {}

// ๐Ÿ‘† Should not throw
// "Property 'a' is missing in type '{}' but required in type 'A<void>'.ts(2741)"

The only problem with the following approach is that a can't be missed from the object:

interface A<T = void> {
  a: T extends void ? undefined : T
}

const a3: A = {}

// ๐Ÿ‘† TS throws
// "Property 'a' is missing in type '{}' but required in type 'A<void>'. ts(2741)"
like image 248
Wenfang Du Avatar asked Oct 28 '25 19:10

Wenfang Du


1 Answers

Why not have undefined as default type for T?

Otherwise, you can have conditional types:

interface A<T = void> {
    a: T extends void ? undefined : T
}

To avoid having a required property with a type of undefined and remove the property completely, try using types instead:

type A<T = void> = T extends void ? Record<string, never> : { a: T }

... where Record<string, never> is a fancy way of denoting an empty object (don't use {}, which means โ€œany non-nullish valueโ€, and would thus accept also e.g. a string). If you then need additional properties that are always there in addition to a, you can write stuff like:

type A<T = void> = T extends void ? Record<string, never> : { a: T } & { b: number }
                                                                     ^^^^^^^^^^^^^^^
like image 51
Jean-Philippe Pellet Avatar answered Oct 31 '25 08:10

Jean-Philippe Pellet