-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Creating object literal with generic key type fails to compile #22060
Comments
@DanielRosenwasser It might, but the intent of that change is to create a union when a computed property's type is a union, so I don't think it will do anything here. |
I think the current behaviour is correct. |
@gcnew - type Pick<T, K extends keyof T> = {
[P in K]: T[P];
} In my understanding, |
What you need is |
@gcnew - Yes, you are right about let _ = require("lodash");
function foo<S>(state: S, key: keyof S) {
let p: Pick<S, keyof S> = _.pick(state, key);
let p1: { [P in keyof S]: S[P] } = p;
} But the following does not: function foo<S>(state: S, key: keyof S) {
let p: Pick<S, keyof S> = {[key]: state[key]};
let p1: { [P in keyof S]: S[P] } = p;
}
// test.ts(2,9): error TS2322: Type '{ [x: string]: S[keyof S]; }' is not assignable to type 'Pick<S, keyof S>'. Again, the question (the bug?) is about creating a new object using generically-typed keys. |
Just in case, to verify that
|
You've stumbled on an issue, but you are interpreting it from the wrong end. The real problem is that function foo<S>(state: S, key: keyof S): S {
let p: Pick<S, keyof S> = _.pick(state, key);
return p;
}
foo({ a: 1, b: 2 }, 'a'); // the return type is `{ a: number, b: number }`
// but the actual value is just `{ a: 1 }` The concept that's missing is that |
@gcnew - Your example seems to imply that let _ = require("lodash");
function foo<S>(state: S, key: keyof S) {
let p: Pick<S, keyof S> = _.pick(state, key);
let s: S = p;
} But I completely fail to understand why - clearly So I'd say that the problem is that |
I see your point - indeed let obj: { a: number, b: number } = { a: 42, b: 43 };
let p: Pick<{a: number, b: number}, keyof {a: number, b: number}> = { a: 42 };
test.ts(8,5): error TS2322: Type '{ a: number; }' is not assignable to type 'Pick<{ a: number; b: number; }, "a" | "b">'.
Property 'b' is missing in type '{ a: number; }'. |
So it seems that quite a lot of typings are affected - aforementioned Is there no way to express |
No, I'm confused again. The following compiles: let _ = require("lodash");
interface State {
a: number;
b: string;
}
class Component<S> {
setState<K extends keyof S>(newState: Pick<S, K>) {
}
}
let component = new Component<State>();
component.setState({ a: 1 }); So Attempting to use object creation syntax fails, object key type is inferred to be function setState2<S, K extends keyof S>(key: K, value: S[K]) {
let component = new Component<S>();
let newState = {[key]: value};
component.setState<K>(newState);
}
test.ts(19,24): error TS2345: Argument of type '{ [x: string]: S[K]; }' is not assignable to parameter of type 'Pick<S, K>'. |
So, again, I want to stress that the only issue here is that in |
This is really a design limitation, please see #21030 for more context. |
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed. |
TypeScript Version: 2.8.0-dev.2018022 or 2.7.2
Search Terms: generic keyof object literal
Code
Expected behavior:
Expected to compile, since I just created a simple literal object.
Actual behavior:
Seems that type is removed from key and replaced with
string
. I'm aware that all object keys are strings, but how do I then create an instance ofPick<S, P>
?Possibly Related Issues: #22053
The text was updated successfully, but these errors were encountered: