-
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
index signature is missing when do object destructuring to separate variable #42021
Comments
This behavior falls out of the inference rules and it's not clear to me which one could be changed given the current type mechanics available. |
Shorter code let { ...obj } = { a: 1 }
let foo: Record<string, number> = obj
// ^
// Type '{ a: number; }' is not assignable to type 'Record<string, number>'.
// Index signature is missing in type '{ a: number; }'.(2322)
let { a } = { a: 1 }
let foo: Record<string, number> = { a }
// ^ this ok |
I've just bumped into this one as well. It feels to me like the destructured object should be assignable to Perhaps interestingly, it turns out if you spread the object into a new one it works whilst the original does not 🤷🏻 const { prop1, ...rest } = { prop1: 'a string', prop2: 2 };
const options1: Record<string, unknown> = rest; // This doesn't work
const options2: Record<string, unknown> = {...rest}; // This does work |
In addition to the last comment if you use const { prop1, ...rest } = { prop1: 'a string', prop2: 2 };
const options1: Record<string, unknown> = rest; // This doesn't work
const options2: Record<string, unknown> = {...rest}; // This does work
const options3: Record<string, any> = rest; // This does work
const options4: Record<string, any> = {...rest}; // This does work |
Now that we have pattern template literal index signatures, this is even more noticeable: interface Foo {
x: string,
[k: `y${string}`]: number;
}
declare const foo: Foo;
const bar = { ...foo, z: true };
// const bar: { z: boolean; x: string; } ... no index signature here |
Can someone comment on why we're not allowing a destructured rest element to have an implicit index signature? The argument in #15300 against doing this for interfaces (i.e., declaration merging issues) doesn't seem to apply here. |
@jcalz can you post a code sample so I can be sure I'm understanding the question? |
Oh, sure, something like this: const foo = (x: Record<string, unknown>) => void 0
const x = { a: 0 }
// const x: { a: number }
foo(x); // okay (implicit index signature, right?)
const { ...y } = x;
// const y: { a: number }
foo(y); // error (no implicit index signature)
// ~ <-- Index signature for type 'string' is missing in type '{ a: number; }' |
The current rule for implicit index signatures is that the originating declaration must be an object type literal, or inferred from an actual object literal (let's call this "objectish"). IOW, types coming from classes or interfaces do not qualify: declare class C {
// In general we cannot assume this list
// of declarations to be exhaustive
a: number;
}
// Error (correct)
foo(new C());
const { ...z } = new C();
// Error (correct)
foo(z);
So I think a reasonable proposal would be to grant |
Not sure if it's the same or a related issue, but I just ran into something that feels similar: spreading an object with an index signature loses the index signature on the result type. type Foo = {[key: string]: string}
const foo: Foo = {a: "b", c: "d"}
const bar = {e: "f", g: "h"}
const baz = {...bar, ...foo}
// Should work, but index signature disappears during spread
const a = baz["a"] My use case was adding some defaults to the index signature object. |
TypeScript Version: 4.1.2
Search Terms:
destructuring, index signature is missing
Expected behavior:
it works
Actual behavior:
when I do object destructuring to separate variable index signature is lost somewhere
Related Issues:
Code
Output
Compiler Options
Playground Link: Provided
The text was updated successfully, but these errors were encountered: