[英]Why doesn't `T extends B` work to limit T to B in future references?
In this TypeScript code , also repeated below, the type PickedAttributeSimpler
is a generic type with a parameter.在这个 TypeScript 代码中,同样在下面重复,类型
PickedAttributeSimpler
是带有参数的泛型类型。 The parameter type is restricted (using extends
) to a pretty small set - in this example, just one specified possibility, but the restriction doesn't have to always be so narrow.参数类型被限制(使用
extends
)到一个非常小的集合 - 在这个例子中,只有一个指定的可能性,但限制不必总是那么窄。
Later in the type definition, I would expect that references to the generic type parameter would be narrowed to the type the parameter was restricted to, ie what's on the right side of the extends
keyword.稍后在类型定义中,我希望对泛型类型参数的引用会缩小到参数所限制的类型,即
extends
关键字右侧的内容。 In any particular use context, it might even be narrower.在任何特定的使用环境中,它甚至可能更窄。 However, in this example and in several more complicated ones eventually boiled down to this one, replacing references to the type parameter with the type that parameter is limited to (to the right of
extends
) produced the desired behavior, allowing TypeScript to figure out the type of the generic as a whole.然而,在这个例子和几个更复杂的例子中,最终归结为这个例子,用参数限制的类型(在
extends
右侧)替换对类型参数的引用产生了所需的行为,允许 TypeScript 找出泛型作为一个整体的类型。
Unfortunately, in practice, some additional narrowing is sometimes needed, where an instance of the type specifies a parameter more specific than the type that parameter must be limited to, and additional references to the generic type parameter are needed to track that through consistently - so just dropping the use of generic type parameters altogether is not a valid solution beyond this simplified example.不幸的是,在实践中,有时需要进行一些额外的缩小,其中类型的实例指定的参数比该参数必须限制的类型更具体,并且需要对泛型类型参数的额外引用以始终如一地跟踪它 - 所以除了这个简化的例子之外,仅仅完全放弃使用泛型类型参数并不是一个有效的解决方案。
Instead, a better understanding is sought of the conditions in which limiting the parameter type will NOT result in later references to the generic type parameter reflecting that narrowing.相反,寻求更好地理解限制参数类型不会导致以后引用反映该缩小的泛型类型参数的条件。
Separate questions address why some simplifications that appear possible from this example such as hard-coding the ObjectModelMap or using a conditional type in ObjectModel don't adequately preserve the issue being demonstrated.单独的问题解决了为什么此示例中可能出现的一些简化(例如硬编码 ObjectModelMap或在 ObjectModel 中使用条件类型)不能充分保留所演示的问题。
It is possible this is due to a bug in TypeScript.这可能是由于 TypeScript 中的错误造成的。 The closest issue I could find is #33014 but that seems to be more specific about functions than defining other types.
我能找到的最接近的问题是#33014 ,但这似乎比定义其他类型更具体地描述了函数。 Maybe I just don't understand what's happening here well enough to search with the right terms or report it.
也许我只是不太了解这里发生的事情,无法使用正确的术语进行搜索或报告。 (Please feel free to file a new bug report there if you think it's appropriate and not duplicative).
(如果您认为合适且不重复,请随时在此处提交新的错误报告)。
The code at the Playground link is: Playground 链接上的代码是:
import BN from "bn.js";
//Simplified version of externally fixed model; many fields omitted for simpler example
type FieldNameWithValueMap = {
Moon: [fieldName: "visibleStarsCount", fieldValue: BN] | [fieldName: "hostStar", fieldValue: string];
Planet: [fieldName: "visibleStarsCount", fieldValue: BN] | [fieldName: "hostPlanet", fieldValue: string];
}
//type PlanetaryBodyName = keyof FieldNameWithValueMap; //'Moon' | 'Planet'; not used for simpler example
type TupleToObject<T extends [string, any]> = { [key in T[0]]: Extract<T, [key, any]>[1] };
type ObjectModel<T extends keyof FieldNameWithValueMap> = TupleToObject<FieldNameWithValueMap[T]>;
//Hovering over these two examples, the types are as expected; they need to be derived from imported types.
type MoonObject2 = ObjectModel<'Moon'>; //{visibleStarsCount: BN; hostPlanet: string;}
type PlanetObject2 = ObjectModel<'Planet'>; //{visibleStarsCount: BN; hostStar: string;}
type DRYObjectModelMap = {
[PlanetaryBodyClass in keyof FieldNameWithValueMap]: ObjectModel<PlanetaryBodyClass>
}
type PickedAttributeSimpler<T extends 'Moon'> = DRYObjectModelMap[T]['visibleStarsCount'];
//The error disappears when the definition below rather than above is used.
//type PickedAttributeSimpler<T extends 'Moon'> = DRYObjectModelMap['Moon']['visibleStarsCount'];
function genericFunction<
T extends 'Moon', //union type that includes | 'Planet' omitted for simpler example.
//Omitting the generic type parameter and hard-coding it into each usage below fixes the error,
//but the real version of the function not oversimplified for the example needs to be generic.
>(
PlanetaryBodyClass: T,
) : PickedAttributeSimpler<T> { //Same if using DRYObjectModelMap[T]['visibleStarsCount']
return new BN(42); //ERROR TS(2322): Type 'BN' is not assignable to type 'PickedAttributeSimpler<T>'.
}
type ExamplePickedAttribute = PickedAttributeSimpler<'Moon'>; //This is type 'BN' as expected
type ExampleGenericPickedAttribute<T extends 'Moon'> = PickedAttributeSimpler<T>; //This is DRYObjectModelMap[T]['visibleStarsCount']
type ExampleGenericInstanceOfPickedAttribute = ExampleGenericPickedAttribute<'Moon'>; //This is BN as expected
type HoverToSeeHowTypeShouldResolve<T extends 'Moon'> = DRYObjectModelMap[T]['visibleStarsCount'];
type HoverToSeeHowTypeShouldResolveInstance = HoverToSeeHowTypeShouldResolve<'Moon'>; //This is BN as expected
Well, typescript is a little bit wierd sometimes.好吧,typescript 有时有点奇怪。
If you use a mapped type of a Union to look up the type value it's working.如果您使用 Union 的映射类型来查找它正在工作的类型值。 It would also work with just "Moon", btw.
顺便说一句,它也适用于“月亮”。 playground
操场
type Union = "Moon"|"Planet"
type Mapped = {[K in Union]:PickedAttributeSimpler<K>}
//The error disappears when the definition below rather than above is used.
//type PickedAttributeSimpler<T extends 'Moon'> = DRYObjectModelMap['Moon']['visibleStarsCount'];
function genericFunction<
T extends Union, //union type that includes | 'Planet' omitted for simpler example.
//Omitting the generic type parameter and hard-coding it into each usage below fixes the error,
//but the real version of the function not oversimplified for the example needs to be generic.
>(
PlanetaryBodyClass: T,
) : Mapped[T] { //Same if using DRYObjectModelMap[T]['visibleStarsCount']
return new BN(42); //No error
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.