The existing answers missed an option, so here's a complete list:
// 1. Explicitly declare the type
var arr: Criminal[] = [];
// 2. Via type assertion
var arr = <Criminal[]>[];
var arr = [] as Criminal[];
// 3. Using the Array constructor
var arr = new Array<Criminal>();
Explicitly specifying the type is the general solution for whenever type inference fails for a variable declaration.
The advantage of using a type assertion (sometimes called a cast, but it's not really a cast in TypeScript) works for any expression, so it can be used even when no variable is declared. There are two syntaxes for type assertions, but only the latter will work in combination with JSX if you care about that.
Using the Array constructor is something that will only help you in this specific use case, but which I personally find the most readable. However, there is a slight performance impact at runtime*. Also, if someone were crazy enough to redefine the Array constructor, the meaning could change.
It's a matter of personal preference, but I find the third option the most readable. In the vast majority of cases the mentioned downsides would be negligible and readability is the most important factor.
*: Fun fact; at the time of writing the performance difference was 60% in Chrome, while in Firefox there was no measurable performance difference.
Answer from Thorarin on Stack OverflowThe existing answers missed an option, so here's a complete list:
// 1. Explicitly declare the type
var arr: Criminal[] = [];
// 2. Via type assertion
var arr = <Criminal[]>[];
var arr = [] as Criminal[];
// 3. Using the Array constructor
var arr = new Array<Criminal>();
Explicitly specifying the type is the general solution for whenever type inference fails for a variable declaration.
The advantage of using a type assertion (sometimes called a cast, but it's not really a cast in TypeScript) works for any expression, so it can be used even when no variable is declared. There are two syntaxes for type assertions, but only the latter will work in combination with JSX if you care about that.
Using the Array constructor is something that will only help you in this specific use case, but which I personally find the most readable. However, there is a slight performance impact at runtime*. Also, if someone were crazy enough to redefine the Array constructor, the meaning could change.
It's a matter of personal preference, but I find the third option the most readable. In the vast majority of cases the mentioned downsides would be negligible and readability is the most important factor.
*: Fun fact; at the time of writing the performance difference was 60% in Chrome, while in Firefox there was no measurable performance difference.
The issue of correctly pre-allocating a typed array in TypeScript was somewhat obscured for due to the array literal syntax, so it wasn't as intuitive as I first thought.
The correct way would be
var arr : Criminal[] = [];
This will give you a correctly typed, empty array stored in the variable 'arr'
Hello,
var arr: [{ name: string }] = [ ] // error
var arr: [{ name: string }] = [ { } ] // works, however, array length is 1 and not 0
How can I initialize it without adding an element inside it? Thank you.
SOLUTION:
simplify the load books function and check for possible null
const loadBooks = (): Ibook[] => {
return JSON.parse(localStorage.getItem('books')!) ?? [];
}update handleSave function to not check for empty arrays and make it less verbose
const handleSave = (): void => {
const savedArr: Ibook[] = [
...loadBooks(),
{ id, title, authors, publishingCompany, saved: true }
];
localStorage.setItem('books', JSON.stringify(savedArr));
setBookSaved(true);
};Original Question Below:
I have a function below that may return an empty array
const loadBooks = ():Ibook[] | [] => {
// @ts-ignore
let savedArr = JSON.parse(localStorage.getItem('books'));
if (!savedArr || !Array.isArray(savedArr)) return [];
else return savedArr;
}I have another function that pushes a book object into the returned array
const handleSave = () => {
let savedArr: Ibook[] | [] = loadBooks();
const bookObj: Ibook = { id, title, authors, publishingCompany };
savedArr.push(bookObj);
localStorage.setItem('books', JSON.stringify(savedArr));
};However, my code will not run because TypeScript says "Argument of type 'Ibook' is not assignable to parameter of type 'never'."
You are not initializing the variable, merely declaring it. After TypeScript removes the type annotations, all that is left in the resulting JavaScript is:
var itemObjects
So just give it a value:
var itemObjects: Item[] = []
^^^^
The other issue (also fixed above) is that [Item] is a tuple of a single Item. At runtime it's just an array, but you can't create one with more or fewer than one Item. Instead, use Item[] to denote an array of items.
You can declare a typed array like the following:
var items = new Array<Item>();
or
var items: Item[] = [];
Both ways will give you exactly same behavior.
Btw why not just use map function instead of forEach?
var items = docs.map((item: any) => new Item(item.amount, item.id));
The definition of string array should be:
// instead of this
// var errors: [string];
// we need this
var errors: string[];
errors = [];
Note: another issue could be the parameter key here
...forEach(function (key) {...
I would guess that we often should declare two of them, because first is very often value, second key/index
Object.keys(response.data.modelState)
.forEach(function (value, key) {
errors.push.apply(errors, response.data.modelState[key]);
});
And even, we should use arrow function, to get the parent as this
Object.keys(response.data.modelState)
.forEach( (value, key) => {
errors.push.apply(errors, response.data.modelState[key]);
});
Missing an obvious answer, needed when not assigning it to a variable: [] as string[]