Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Alias type for indexing a generic object with transform breaking change in 4.2.2+ #44054

Closed
iPherian opened this issue May 12, 2021 · 6 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Milestone

Comments

@iPherian
Copy link

iPherian commented May 12, 2021

Bug Report

πŸ”Ž Search Terms

index generic with alias, alias generic

πŸ•— Version & Regression Information

  • This changed between versions 4.1.5 and 4.2.2
    • Still broken in 4.2.4 and nightly

⏯ Playground Link

Playground link

πŸ’» Code

type ValOf<T> = T[keyof T];

const base = {
  color: "green",
} as const;

function getFromPropsNotShared<MoreProps extends {}>(
  combined: PropsNotShared<typeof base, MoreProps>,
  prop: keyof PropsNotShared<typeof base, MoreProps>
): /**
 * Produces error in typescript 4.2.x but succeeds in 4.1.5
 *
 * Succeeds if you replace the ValOf<...> type annotation with
 *
 * PropsNotShared<typeof base, MoreProps>[
 *     keyof PropsNotShared<typeof base, MoreProps>
 * ]
 *
 * (which seems like it means the same)
 */
ValOf<PropsNotShared<typeof base, MoreProps>> {
  return combined[prop];
}

type PropsNotShared<LHS extends {}, RHS extends {}> = Omit<RHS, keyof LHS> &
  Omit<LHS, keyof RHS>;

πŸ™ Actual behavior

Says the value returned by getFromPropsNotShared() is not assignable to the annotated return type. Works if you replace it with a similar annotation without using the ValOf generic. ValOf is awfully convenient though especially for longer type expressions.

πŸ™‚ Expected behavior

Would expect it to succeed, because the ValOf alias that fails seems like it means the same as what works ( manually write out T[keyof T] ) but cleaner to write. Also because it worked in 4.1.5.

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label May 12, 2021
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone May 12, 2021
@RyanCavanaugh
Copy link
Member

A shorter repro would be appreciated; I'm sure this can be cut down quite a bit.

@iPherian
Copy link
Author

@RyanCavanaugh okay shortened it

@iPherian iPherian changed the title Alias type for indexing a generic object with custom object copying breaks in 4.2.2+ Alias type for indexing a generic object with custom transformation breaking change in 4.2.2+ May 12, 2021
@iPherian iPherian changed the title Alias type for indexing a generic object with custom transformation breaking change in 4.2.2+ Alias type for indexing a generic object with transform breaking change in 4.2.2+ May 12, 2021
@RyanCavanaugh
Copy link
Member

This example in 4.1 just returns any. I suspect we were incorrectly computing the type in a non-error-reporting context and the error didn't get reported:

type ValOf<T> = T[keyof T];

const base = {
  color: "green",
} as const;

function getFromPropsNotShared<MoreProps extends {}>(
  combined: PropsNotShared<typeof base, MoreProps>,
  prop: keyof PropsNotShared<typeof base, MoreProps>
): /**
 * Produces error in typescript 4.2.x but succeeds in 4.1.5
 *
 * Succeeds if you replace the ValOf<...> type annotation with
 *
 * PropsNotShared<typeof base, MoreProps>[
 *     keyof PropsNotShared<typeof base, MoreProps>
 * ]
 *
 * (which seems like it means the same)
 */
ValOf<PropsNotShared<typeof base, MoreProps>> {
  return combined[prop];
}

type PropsNotShared<LHS extends {}, RHS extends {}> = Omit<RHS, keyof LHS> &
  Omit<LHS, keyof RHS>;

const p = getFromPropsNotShared({length: 0, color: "green"}, "length");
p.asdf; // no error

@RyanCavanaugh RyanCavanaugh added Working as Intended The behavior described is the intended behavior; this is not a bug and removed Needs Investigation This issue needs a team member to investigate its status. labels May 13, 2021
@iPherian
Copy link
Author

iPherian commented May 14, 2021

@RyanCavanaugh Hmm I think that's just because it wasn't inferring the generic type parameter exactly, if you change it to do so it does error there:

playground

type ValOf<T> = T[keyof T];

const base = {
  color: "green",
} as const;

function getFromPropsNotShared<MoreProps extends {}>(
  combined: PropsNotShared<typeof base, MoreProps>,
  prop: keyof PropsNotShared<typeof base, MoreProps>
): /**
 * Produces error in typescript 4.2.x but succeeds in 4.1.5
 *
 * Succeeds if you replace the ValOf<...> type annotation with
 *
 * PropsNotShared<typeof base, MoreProps>[ keyof PropsNotShared<typeof base, MoreProps> ]
 *
 * (which seems like it should mean the same)
 */
ValOf<PropsNotShared<typeof base, MoreProps>> {
  return combined[prop];
}

type PropsNotShared<LHS extends {}, RHS extends {}> = Omit<RHS, keyof LHS> &
  Omit<LHS, keyof RHS>;


const p = getFromPropsNotShared /* precise generic type param */ <{length: 0}>({length: 0, color: "green"}, "length");
p.asdf; // now error

Furthermore, given that:

type ValOf<T> = T[keyof T];

...the part that seems most strange to me is where in 4.2 (but not in 4.1), an error will be produced when getFromPropsNotShared() is annotated return:

ValOf< PropsNotShared<typeof base, MoreProps> >

but not when annotated with return (in either 4.2 or 4.1):

PropsNotShared<typeof base, MoreProps>[ keyof PropsNotShared<typeof base, MoreProps> ]

Which is weird, right? Because the only difference is Replacing T in ValOf with the actual expression of the parameter. In my mind at least it seems like they should do the same.

Between both 4.1 and 4.2 there are correctly errors (i.e. not any) in your example if explicit type params are given:

const p = getFromPropsNotShared /* precise generic type param */ <{length: 0}>({length: 0, color: "green"}, "length");
p.asdf; // now error

@RyanCavanaugh
Copy link
Member

@iPherian can you reduce this to a minimal repro of what you think the bug is and log a new issue? Thanks!

@iPherian
Copy link
Author

@RyanCavanaugh okay opened a new issue #44095

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

2 participants