英文:
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<T, T1 = string, T2 = boolean> {
    ID: T
    Name: T1
    IsActive: T2
}
There is 3 type parameters are following:
T-- it's requiredT1-- optional, default isstringT2-- optional, default isboolean
I want to create data with specification below:
T--numberT1-- <DEFAULT which isstring>T2--number
const data:Foo<number, ..., number> = {
    ID: 1,
    Name: "apache", // 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,
}
英文:
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,
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论