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

Improperly widened computed property keys in the presence of generics + literal types #41779

Closed
carlpaten opened this issue Dec 2, 2020 · 4 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@carlpaten
Copy link

TypeScript Version: 4.2.0-dev.20201202

Search Terms: computed property

Code

function obj<T extends string>(key: T) {
  return { [key]: 0 };
}
const result: { foo: number } = obj<"foo">("foo");

Expected behavior: this should compile without error.

Actual behavior: error TS2741: Property 'foo' is missing in type '{ [x: string]: number; }' but required in type '{ foo: number; }'.

Playground Link: https://www.typescriptlang.org/play?ts=4.2.0-dev.20201202#code/GYVwdgxgLglg9mABHARgKwDwBVEFMAeUuYAJgM6JlQBOMYA5gHwAUA1rgJ4BciWAlIgDeAKESJquKCGpJBiANrsOAXR4AGRAF8A3MM3CICKuNxkQAGyg85wOHB5gQAWxS5qWxAF5k6DACJbOD8WALs-Pl0gA

Related Issues:

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Dec 3, 2020
@RyanCavanaugh
Copy link
Member

This is the correct behavior. If you imagine that we inferred obj's return type to be Record<T, number> then this code would be allowed, but it's unsound:

function obj<T extends string>(key: T) {
  return { [key]: 0 };
}

const result: { bar: number } = obj<"foo" | "bar">("foo");
result.bar.toFixed();

@carlpaten
Copy link
Author

I thought this was incorrect behavior because the specialized version of the function has the expected type {foo: number}, but now I realize that in order to accomplish that you'd need the return type of obj to be something like T is literal ? Record<T, number> : { [x: string]: number; }, and is literal does not exist in TypeScript. Sorry for the erroneous report, and thank you for the explanation!

@RyanCavanaugh
Copy link
Member

np, it's tricky!

@grapereader
Copy link

Return type for obj<"foo" | "bar">("foo") should be { foo?: number, bar?: number } but for obj<"foo">("foo") it can be { foo: number }

Even if you do widen the domain of keys to all strings, inferred type should be { [x: string]?: number; } because not every string key will be defined. It is still unsound.

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

3 participants