Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Leave as default type on generic type parameter

Tags:

typescript

I am trying to bypass some optional generic type parameter and leave it as a default that has been defined.

This is an example script:

interface Foo<T, T1 = string, T2 = boolean> {
    ID: T
    Name: T1
    IsActive: T2
}

There is 3 type parameters are following:

  • T -- it's required
  • T1 -- optional, default is string
  • T2 -- optional, default is boolean

I want to create data with specification below:

  • T -- number
  • T1 -- <DEFAULT which is string>
  • T2 -- number
const data:Foo<number, ..., number> = {
    ID: 1,
    Name: "apache", // the name type should be a string
    IsActive: 1,
}
like image 465
Luthfi GearIntellix Avatar asked Sep 14 '25 21:09

Luthfi GearIntellix


1 Answers

There is currently no such syntax to "skip" a generic type argument, either for the purposes of using a default or for having the compiler infer the type argument. There is a longstanding open feature request for this at microsoft/TypeScript#26242; if that is ever implemented, then maybe you'll be able to write Foo<number, , number> or Foo<number, *, number>, or Foo<number, infer, number> or something.

Until then, you'll just have to write the type in yourself as Foo<number, string, number>, or work around it somehow.


One possible workaround, if the purpose of "skipping" is to get the default, is to make a custom type to mean "skip" and rewrite your type to recognize that. For example:

interface $ { ___SIGIL___: true; } // $ means "skip"
type Default<T, U> = [T] extends [$] ? U : T;

And now instead of type F<T = X, U = Y, V = Z> you'd write type MyF<T = $, U = $, V = $> = F<Default<T, X>, Default<U, Y>, Default<V, Z>>. For your Foo it look s like:

type FooT1Default = Foo<any> extends Foo<any, infer T1, any> ? T1 : never;
// type FooT1Default = string

type FooT2Default = Foo<any> extends Foo<any, any, infer T2> ? T2 : never;
// type FooT2Default = boolan

type MyFoo<T, T1=$, T2=$> = 
  Foo<T, Default<T1, FooT1Default>, Default<T2, FooT2Default>>;

And we can test it:

type Example = MyFoo<number, $, number>
// type Example = Foo<number, string, number>

const data: MyFoo<number, $, number> = {
    ID: 1,
    Name: "apache", // okay
    IsActive: 1,
}

Playground link to code

like image 128
jcalz Avatar answered Sep 16 '25 09:09

jcalz