Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

infer keyword to get generic type from base class

Consider the following class

class SomeBaseClass<T extends string | number> {
    ...
}

And the following conditional type using the infer keyword

type ExtractInner<T> = T extends SomeBaseClass<infer U> ? U : T;

With this, we can extract the generic type used in SomeBaseClass like this (this is from the docs, more or less)

type InferredString = ExtractInner<SomeBaseClass<string>>  // InferredString is just type string

In my slightly more advanced scenario, the following is the case

class StringVersion extends SomeBaseClass<string> {
    ...
}
class NumberVersion extends SomeBaseClass<number> {
    ...
}

How may one define a type ExtractInnerWithExtend such that it is the equivalent to ExtractInner? I.e.:

type InferredStringWithExtend = ExtractInnerWithExtend<StringVersion>  // InferredStringWithExtend should be string
type InferredNumberWithExtend = ExtractInnerWithExtend<NumberVersion>  // InferredStringWithExtend should be number

Using ExtractInner in this scenario will result in simply string | number, I was actually expecting to get either string or number, not the union type. Is this maybe a bug? Is what I'm trying possible?

Many thanks in advance.

like image 417
Maurits Moeys Avatar asked Nov 17 '18 23:11

Maurits Moeys


1 Answers

ExtractInner will work on the derived version of the types with one condition: that you actually use the type in the base class in some way

class SomeBaseClass<T extends string | number> {

  private value!: T

  // Any of these will also work
  //value!: T
  //m(v:T): void {}
  //m(): T { return null as any }
}

type ExtractInner<T> = T extends SomeBaseClass<infer U> ? U : T;


class StringVersion extends SomeBaseClass<string> {}
class NumberVersion extends SomeBaseClass<number> {}

type InferredStringWithExtend = ExtractInner<StringVersion>  // string
type InferredNumberWithExtend = ExtractInner<NumberVersion>  // number

The reason for this behavior is the structural nature of the typescript type system, type structure matters more then the inheritance declarations.

like image 162
Titian Cernicova-Dragomir Avatar answered Nov 03 '22 17:11

Titian Cernicova-Dragomir