Home > Enterprise >  `Required` does not remove `undefined` from class generic properties (bug?)?
`Required` does not remove `undefined` from class generic properties (bug?)?

Time:03-17

I stumbled accross the following situation for the standard utility type Required:

type A = {x?: number;}
type B1 = Required<A>['x']; // number, OK
type B2<T extends A> = Required<T>['x']; // number, OK
class C1 {
  public f(x: Required<A>['x']) { // x is number, OK
    const y = x   1; // OK
  }
}
class C2<T extends A> {
  public f(x: Required<T>['x']) { // x is number | undefined, NOT OK
    const y = x   1; // ERROR
  }
}

I cannot imagine that this is expected behavior. Why is the C2-case different from the C1-case? I thought at first it may have something to do with generics in general, but only class generics seem to be affected since the B2-case works.

Can I do anything - other than explicitly saying something like x: Exclude<Required<T>['x'], undefined> - to make x (and potentially other properties of A) really required (i.e. not undefined)?

CodePudding user response:

So, the answer is that T is not equal with A. It means that T can be another type, that can do something and implements keys from A if you want them to be equal you need to do this.

class C2<T extends Required<A>> {
  public f(x: Required<T>["x"]) {
    // x is number, OK
    const y = x   1; // OK
  }
}

Here, we’ll create an interface that has a single .length property and then we’ll use this interface and the extends keyword to denote our constraint:

Generics docs

UPD:

Required makes from {x?: number} -> {x: number}.

But if call

Required<{x: number | undefined}> The x still undefined.

When you pass T to generic then field?: someType converts to field: someType | undefined.

In your case you should get rid of undefined twice, the ? and undefined type as well.

type FullRequired<T extends object> = Required<{
  [K in keyof T]: Exclude<T[K], undefined>;
}>;

class C2<T extends A> {
  public f(x: FullRequired<T>["x"]) {
    // x is number  OK
    const y = x   1; // OK
  }
}
  • Related