保持在通用类型参数上的默认类型

huangapple go评论68阅读模式
英文:

Leave as default type on generic type parameter

问题

const data: Foo<number, string, number> = {
    ID: 1,
    Name: "apache",
    IsActive: 1,
}
英文:

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&lt;T, T1 = string, T2 = boolean&gt; {
    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 -- &lt;DEFAULT which is string&gt;
  • T2 -- number
const data:Foo&lt;number, ..., number&gt; = {
    ID: 1,
    Name: &quot;apache&quot;, // the name type should be a string
    IsActive: 1,
}

答案1

得分: 2

目前还没有这样的语法来“跳过”一个通用类型参数,无论是为了使用默认值还是为了让编译器推断类型参数。这方面有一个长期存在的开放功能请求,可以在microsoft/TypeScript#26242中找到;如果这个功能被实现,那么也许你就能够编写类似于Foo<number, , number>Foo<number, *, number>Foo<number, infer, number>之类的代码。

在那之前,你只能自己写类型,比如Foo<number, string, number>,或者以某种方式绕过它。

一个可能的解决方法,如果“跳过”的目的是为了获取默认值,是创建一个自定义类型来表示“跳过”,然后重新编写你的类型以识别它。例如:

interface $ { ___SIGIL___: true; } // $ 表示“跳过”
type Default<T, U> = [T] extends [$] ? U : T;

现在,不再使用type F<T = X, U = Y, V = Z>,而是写成type MyF<T = $, U = $, V = $> = F<Default<T, X>, Default<U, Y>, Default<V, Z>>。对于你的Foo类型,看起来是这样的:

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 = boolean

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

我们可以进行测试:

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

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

Playground链接到代码

英文:

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&lt;number, , number&gt; or Foo&lt;number, *, number&gt;, or Foo&lt;number, infer, number&gt; or something.

Until then, you'll just have to write the type in yourself as Foo&lt;number, string, number&gt;, 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 &quot;skip&quot;
type Default&lt;T, U&gt; = [T] extends [$] ? U : T;

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

type FooT1Default = Foo&lt;any&gt; extends Foo&lt;any, infer T1, any&gt; ? T1 : never;
// type FooT1Default = string

type FooT2Default = Foo&lt;any&gt; extends Foo&lt;any, any, infer T2&gt; ? T2 : never;
// type FooT2Default = boolan

type MyFoo&lt;T, T1=$, T2=$&gt; = 
  Foo&lt;T, Default&lt;T1, FooT1Default&gt;, Default&lt;T2, FooT2Default&gt;&gt;;

And we can test it:

type Example = MyFoo&lt;number, $, number&gt;
// type Example = Foo&lt;number, string, number&gt;

const data: MyFoo&lt;number, $, number&gt; = {
    ID: 1,
    Name: &quot;apache&quot;, // okay
    IsActive: 1,
}

Playground link to code

huangapple
  • 本文由 发表于 2023年7月20日 21:16:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76730314.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定