Reputation: 23
there is a riddle about Typescript I cannot understand:
const randomFn = (arg: Record<string, unknown>): string => 'kappa'
export type Values = {
key: string;
};
const values: Values = {
key: 'kappa'
}
const { ...spread } = values;
randomFn(values)
randomFn(spread) // produce Index signature for type 'string' is missing in type '{ transaction: string; }'.(2345)
Why is Typescript producing errors for spread object when in my understanding it typing should be the same. If we inspect the object in playgroud it is exactly the same for TS compiler. Both original and spreaded.
TS version 4.5.4. Reproduction in Type Script Playground
EDIT: also doing double spread to make it work again .
randomFn({...spread}) // NO error
Upvotes: 2
Views: 152
Reputation: 329523
This is the result of a design limitation of TypeScript, see microsoft/TypeScript#42021 for details. When you use a rest element in an object destructuring assignment, TypeScript unfortunately does not copy an index signature into the type of the new variable. Nor does it allow the variable to have an implicit index signature (although I'm not sure why).
Your Values
type alias is allowed to have an implicit index signature (if you made it an interface
then it wouldn't either, see microsoft/TypeScript#15300), so it is considered assignable to Record<string, unknown>
(which is equivalent to {[k: string]: unknown}
, a type with a string index signature). But spread
, as a rest-destructured variable, is not, and therefore it fails.
You noticed that doing a second rest destructuring does work, so presumably there's something weird about how object types get marked to allow or disallow implicit index signatures. This is also noted in microsoft/TypeScript#42021, although without explanation.
So unfortunately there's not a very satisfying answer to be had right now, unless more activity happens in microsoft/TypeScript#42021.
Upvotes: 0
Reputation: 26344
Spreading loses the type because it has no guarantee that the type of the spread object is the same. Consider this:
const { excluded, ...rest } = object;
Clearly rest
can't be the same type as object
; there is a key missing!
You can also think of it like this:
const [excluded, ...rest] = array;
That's why spread
is not type Values
.
Upvotes: 1