Description
Bug Report
🔎 Search Terms
Mapped Types, Conditionals, Template Types, Index Types, Index Signature
🕗 Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about Mapped Types
⏯ Playground Link
Playground link with relevant code
💻 Code
Below we use the following as a placeholder type. The specific "value" type in these examples is immaterial.
type AValue = { hello: 'world' };Example 1
In the below example, t0 will be of type string because T will have type string instead of the narrower string literal type you might expect. This is the result with or without as T in the index signature but is even more surprising given the cast.
This example is important only in that it establishes how T has type string, the ramifications of this are more clear in the examples following.
type MappedTypeWithKeyReturn = {
[T in string as T]: T;
}
// type should be 'aKey' not string
type t0 = MappedTypeWithKeyReturn['aKey'];Example 2
A slightly more complex example showing we cant use extends in the value portion as might be expected. This example fails even if we do T in string as T for the index signature, and fails even when V is not a generic but statically known.
type MappedTypeWithConditionalValue<V extends string, R> = {
[T in string]: T extends V ? R : unknown;
}
// type should be { hello: 'world' } not unknown
type t1 = MappedTypeWithConditionalValue<'aKey', AValue>['aKey'];Example 3
This example shows we cannot use an extends check properly within the index signature for any V that
is not simply string.
type MappedTypeWithConstraint<V extends string, R> = {
[T in string as T extends V ? T : never]: R;
}
// type should be { hello: 'world' } not an error
type t2 = MappedTypeWithConstraint<'aKey', AValue>['aKey'];Example 4
A more complex example showing that the above issues prevent using a template string check
with a mapped type, via either index or value approach.
type IndexStr = `com.some.thing.${string}`;
// type should be { hello: 'world' } not unknown
type t3 = MappedTypeWithConditionalValue<IndexStr, AValue>['com.some.thing.foo'];
// type should be { hello: 'world' } not an error
type t4 = MappedTypeWithConstraint<IndexStr, AValue>['com.some.thing.foo'];🙁 Actual behavior
Was not able utilize a conditional type within either the index signature or the value of a mapped type.
🙂 Expected behavior
Should be able utilize a conditional type within either the index signature or the value of a mapped type.
Activity
runspired commentedon Jun 17, 2021
Closing because what I was missing is that mapped types eagerly resolve their type, so
stringhere is correct and is also not serving as "the union of all strings". If a union could be constructed this pattern will work, unfortunately in my case a union cannot be constructed, and the solution I need is #26797