Home > database >  Override only some of the generic variables
Override only some of the generic variables

Time:10-22

Consider the following scenario:

class Test<A extends myObjectType = myObjectType, B extends myOtherObjectType = myOtherObjectType> {};

const TestValue: Test<myObjectType, myChangedObjectType> = ...

Is it possible somehow, to only override SOME of the generic variables which have a default value assigned to them?

What I would want to achieve, is the ability, to do something like this:

class SecondTest extends <_, myChangedObjectType> { ... }

and I would like Typescript to know, that by ommiting the first generic parameter (by providing to it a default value, for example _), I am referring to the the default value of the original class.

CodePudding user response:

As @T.J.Crowder said, there is no way to mutate or override generic argument.

However there is a workaround. You can create new type which inherits first argument from previous type and add new generic type

type myObjectType = {
  tag: 'myObjectType'
}
type myOtherObjectType = {
  tag: 'myOtherObjectType'
}

class Test<A extends myObjectType = myObjectType, B extends myOtherObjectType = myOtherObjectType> { };


type Change<
  Class extends Test<any, any>,
  NewType extends myOtherObjectType> =
  (Class extends Test<infer Type, infer _>
    ? (Type extends myObjectType
      ? Test<Type, NewType>
      : never)
    : never)

type Changed = Change<Test<myObjectType, myOtherObjectType>, myOtherObjectType & { greet: 'hello' }>;

declare var changed: Changed;

Playground

You can infer only first generic type and construct new type with first generic type and new second generic type.

CodePudding user response:

You can't specify a later type argument if you've left a previous type argument unspecified. Here's a link to the 2.3 docs on type parameter defaults but I don't think it's changed (the v.4.4.4 playground won't let me do it).

So you could leave off the second type argument in your example (Test<something>), or both of them (Test), but you can't leave off just the first one while specifying the second (Test</*nothing here*/, something>).

  • Related