英文:
Extract template parameter from Generic type
问题
我知道如何从string[]
中提取string
,但这让我头疼:
type bla<T = number> = 123;
// 给定只有 "bla",在这种情况下如何提取模板参数 "number"?
type T = bla extends bla<infer U> ? U : never;
我认为在4年前这是不可能的,但也许有些变化了。
英文:
I know how to extract string
from string[]
but this is giving me a headache:
type bla<T = number> = 123;
// given just "bla", how can I extract the template parameter "number" in this case?
type T = bla extends bla<infer U> ? U : never;
I think this wasn't possible 4 years ago but maybe something has changed.
答案1
得分: 2
最大的问题在于你的 通用 类型参数未被使用:
type Foo<T = number> = 123;
type Oops = Foo extends Foo<infer U> ? U : never;
// type Oops = unknown
这里 Foo<T>
对于任何 T
都将是 123
。 TypeScript 的类型系统应该是 结构化的,而不是 名义化的。所以如果没有对 T
的结构依赖,从 Foo<T>
推断出 T
将是不可靠的,即使有时候它能够工作。这就是为什么 TypeScript FAQ 不鼓励不使用它们的类型参数的通用类型。
接下来的最大问题是 TypeScript 完全不使用 默认类型参数 进行推断,正如 microsoft/TypeScript#42064 中所述。
所以即使 TypeScript 类型被名义化对待,你可能也得不到你所期望的行为。将此与 约束 进行比较,它至少在推断中有所参与:
type Bar<T extends number = number> = 123;
type Hmm = Bar extends Bar<infer U> ? U : never;
// type Hmm = number
对于 Foo<T>
同样的论点会暗示 Bar<T>
也会失败,但这里你会得到 number
而不是 unknown
。这是因为在无法推断时编译器会退而求其次地使用约束。因此,尽管 Bar<T>
对于所有的 T
都是 123
,但在 T
上仍然存在一个 number
约束可以使用。
将这两者结合在一起,这意味着你所做的是不可能的。你需要重构以使用类型参数,然后确保明确提及没有类型参数的类型,以便让编译器替换默认值,只有这样才有可能正确地推断类型。
英文:
The biggest problem here is that your generic type parameter is unused:
type Foo<T = number> = 123;
type Oops = Foo extends Foo<infer U> ? U : never;
// type Oops = unknown
Here Foo<T>
is going to be 123
for any T
whatsoever. TypeScript's type system is supposed to be structural and not nominal. So without a structural dependence on T
, inference of T
from Foo<T>
will not be reliable, even if you can get it to work sometimes. That's why the TypeScript FAQ discourages any generic types that don't use their type parameters.
The next biggest problem is that TypeScript just does not use default type arguments for inference at all, as mentioned in microsoft/TypeScript#42064 .
So even if TypeScript types were treated nominally, you might not get the behavior you are looking for. Compare this to constraints, which at least participate somewhat in inference:
type Bar<T extends number = number> = 123;
type Hmm = Bar extends Bar<infer U> ? U : never;
// type Hmm = number
The same argument for Foo<T>
would imply that Bar<T>
would also fail to work, but you get number
instead of unknown
here. And that's because the compiler will fall back to the constraint when failing to infer. So even though Bar<T>
is 123
for all T
, there's still a number
constraint on T
that can be used.
Put both of those together and it means that what you're doing isn't possible. You'd need to refactor to use the type parameter and then be sure to explicitly mention the type without a type argument to get the compiler to substitute in the default, and only then would it be likely that you could infer the type properly.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论