-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Cannot assign property to same type with generic key #32693
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
Comments
See #30769 and #31445. The compiler only sees the types when checking the assignment and doesn't realize that This used to work prior to #30769 (TS 3.5), but only as a consequence of being unsound in general: type A = { a: number }
type B = { b: number }
interface Foo {
a: A
b: B
}
declare let target: Foo
declare let source: Foo
declare let k1: keyof Foo
declare let k2: keyof Foo
// this was incorrectly allowed before TS 3.5
target[k1] = source[k2] |
I think the title is slightly misleading here: the key in your example is not generic and #30769 specifically does not affect assignments where the key is generic. function assignProp<K extends keyof Foo>(target: Foo, source: Foo, key: K) {
target[key] = source[key]; // no error
} |
In a sense |
#31445 is the canonical one for this problem. That said, I think we should revisit since it seems to be coming up reasonably often. Special-casing |
Yes, please consider special case handling. In our project we have to stick on interface O {
a?: (object|string);
b?: string;
}
function B (p?: ('a'|'b')): void {
var o: O = {};
if (p) {
o[p] = o[p] || {};
}
} |
CC @medns |
Approved for the case where
where |
related to explanation from @RyanCavanaugh Your code makes sense, but it is a different case from the one I submitted. You proposed general case and x[g] is not assignable to x[f]. However its a bit tricky and special case should be considered. So, if the indexer is the same type than operation should be allowed. type SimpleType = { a: string, b: number }
let x,y: SimpleType = { a: "", b: 9 }
let fields: (keyof SimpleType)[] = ["a", "b"]
for (const g of fields) {
for (const f of fields) {
x[f] = x[g] //OK (Error -> and should not be allowed; type are not same: each one is string|number )
y[f] = x[f] //Error -> but is OK (types are the same: each one is string or each one is number)
x[f] = x[f] //Error -> but is OK (types are the same)
let h = (Math.random() > 0.5) ? fields[0] : fields[1]
y[h] = x[x] //Should be an error
let j = f
y[j]=x[f] //Would be nice if the complier let this compile to
}
} Proposal:
for (const f of /*keyword_of_mapped_field*/ fields) and implement additional indexer instance check
y[/*keyword_of_mapped_indexer(*/f/*)*/]= y[/*keyword_of_mapped_indexer(*/g/*)*/] and implement additional indexer instance check |
Very much looking forward to the special case getting implemented at some point. We just ran across this in a slightly different scenario [Playground]: interface test
{
a: number;
b: boolean;
}
const x: test = { a: 0, b: false };
const y: test = { a: 1, b: true };
// Is Okay:
const simple: keyof test = "b";
x[simple] = y[simple]; // <-- All good!
// Is Bad:
const props: Array<keyof test> = ["a", "b"];
for (const prop of props)
{
// Type 'number | boolean' is not assignable to type 'never'.
// Type 'number' is not assignable to type 'never'.(2322)
x[prop] = y[prop]; // <-- Error!
} |
@ericdrobinson Just to clear up any potential confusion, your "simple case" works because |
@fatcerberus Ahh, yes, good point. Definitely better to be clear on that for this issue. Your pointer also made me realize that there's an even simpler example that shows the issue [Playground]: interface test
{
a: number;
b: boolean;
}
const x: test = { a: 0, b: false };
const y: test = { a: 1, b: true };
declare const prop: keyof test;
// Type 'number | boolean' is not assignable to type 'never'.
// Type 'number' is not assignable to type 'never'.(2322)
x[prop] = y[prop]; // <-- Error! |
TypeScript Version: 3.6.0-dev.20190803
Search Terms: assigning keyof generic key
Code
Expected behavior:
I expect it to allow the assignment. Since
typeof target
andtypeof source
are the same, I expecttypeof target[key]
to always be the same astypeof source[key]
.Actual behavior:
Playground Link: https://www.typescriptlang.org/play/#code/C4TwDgpgBAglC8UDeUCGAuKA7ArgWwCMIAnKAXwChRIoAhBZKAzXQk8iigSy2BIDNUAY2gAxAPbjkFKLLSYYMuczoVKFACYQhAG1TFoOiMCjB9Ac2OYJ4zdr0GoRkwGdxOYiOuS7u-YeMoAGsIEEwQkHF+KBtOM2JLYABtCIBdBjcPERTQ1IogA
Related Issues: #31665 (but it was closed and the comments seem to indicate that this should work 🤔) ping @RyanCavanaugh
The text was updated successfully, but these errors were encountered: