I have a Javascript object challenge which I cannot translate to Typescript.
var someData = [
'Some String',
{'age': '46'}
];
const addressObject = {
street: 'Main Street',
number: '14'
}
const resultObject = {
address: addressObject,
...someData[1]
}
console.log(resultObject)
Result is, and should be:
{ address: { street: 'Main Street', number: '14' }, age: '46' }
In TypeScript, I cannot figure out how to get the second element in someData
to be spread in the resultObject
.
Tried the spread operator in various forms:
...someData[1] // "Property assignment expected"
[...someData[1]] // "Expression expected"
Even if I only take the second prop of someData:
const someData_1 = someData[1]
const resultObject = {
address: addressObject,
...someData_1
}
Same error.
Complexity is probably in original someData
array which has a string as first element and object as second element, which none of the other TypeScript/spread example/articles have.
2
Answers
Try this:
My output:
npx ts-node src/test.ts
By default TypeScript will infer that an array literal has a plain array type, where each element is of the same type. Your
someData
is therefore treated like an array where each element might be astring
or an{age: string}
. The compiler intentionally doesn’t keep track of which types might appear at which indices, because often people would like to change the contents of their arrays, and such information would be impossible to maintain in such a scenario (at least given TypeScript’s type system, in which values types don’t arbitrarily mutate).But you don’t want to use
someData
as an abitrary array of strings-or-age-havers. Instead, you want it to be a constant set of data where the first element is a string and the second is an age-haver and there are no elements at other indices. The inference algorithm, while reasonable for a wide range of real-world code, didn’t do what you wanted. So you need to make a change.There are various ways to change the typings here. You could annotate or assert the type of
someData
.But the easiest way to express the intent that
someData
‘s structure won’t change is to use a const assertion:This still uses TypeScript’s inference algorithm, but you’re giving the compiler a hint that you don’t plan to mutate the data structure and that you do care about all the literal types and their positions. Now the type of
someData
isa tuple type where the positions of the various data, including the literal types of their string values, are known.
And now
someData[1]
is known to be an{age: "46"}
, so you can spread it into a new object without the compiler worrying that you might be spreading a string:Playground link to code