Skip to content

Conditionals checks of the key used with Mapped Types don't work as expected #44625

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
runspired opened this issue Jun 17, 2021 · 1 comment
Closed

Comments

@runspired
Copy link

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.

@runspired
Copy link
Author

Closing because what I was missing is that mapped types eagerly resolve their type, so string here 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

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant