JavaScript supports two basic data structures for storing information, Arrays and Hashes. Let's look at how we might add an Array and a Hash to a View Model.
Arrays
TypeScript arrays can be defined and initialized in two ways, with the Array<T>
type, or T[]
type. Both of these are equivalent, but one or the other may be easier to write depending on the situation. Also, for compatibility with Internet Explorer, Cascade provides an interface IArray<T>
, but we will cover that in more depth later.
So, if we were to create an Array of string
elements, it would be.
let list: string[] = [];
This code simply creates an variable called list
, defined as an string[]
and initializes it to be an empty Array
. It is important to note that we have initialized this variable, otherwise it would equal undefined
.
Now that we have created an Array
, we can access its values with a regular Assignment Operator
. We can read and write values with:
let value = list[0];
list[1] = 2;
We can also use any of the Array
methods, such as Array.prototype.push(value: any): void;
list.push(3);
Hashes
Next, we have JavaScript Hashes, which are actually just regular Objects.
TypeScript Hashes can be defined as an interface
, which stores elements with either string
or number
indexes. JavaScript allows for mixing index types, but TypeScript requies it to be one or the other. Since we already have support for number
indexes with Arrays, Cascade defines Hash types as:
interface IHash<T> {
[index: string]: T;
}
For ease of use, IHash
may be imported from Cascade.
External Links
For more information on Arrays, visit Array - JavaScript | MDN
For more information on Objects, visit Objects - JavaScript | MDN
View Models
We may store Arrays and Hashes as properties on a View Model. For example:
class ViewModel {
list = [];
map = {};
}
However, just like regular properties, changes to these properties will be ignored. Again, if we add our decorators, we can subscribe to changes.
class ViewModel {
@array list = [];
@hash map = {};
}
It's important to note that once an Array or Hashe is marked as observable, Cascade will automatically set its value to be an Array or Hash, even if we haven't initialized it. We don't even have to write an initialization in the code. Plus, we don't have to check if the property is truthy before doing lookups on it. All of that is handled by Cascade!
So, we can simply write:
class ViewModel {
@array list;
@hash map;
}
We can also be more specific about what is stored in Arrays and Hashes.
class ViewModel {
@array list: string[];
@hash map: IHash<string>;
}
Reflection Polyfill
By default, Arrays must be decorated with @array
and Hashes with @hash
. However, just like we can use @observable
to decorate Computed
properties, we can also use it to decorate Arrays, but only with some extra libraries.
In order to get this automatic type detection, we have to set up an experimental TypeScript Metadata feature. First off, you must set "emitDecoratorMetadata": true
in your tsconfig.json
file. Then, you must install the package reflect-metadata
from npm.
Furthermore, for IE10 and below, you must also include es6-shim
or similar polyfills.
Then, in your main TypeScript file, you must include:
import 'es6-shim';
import 'reflect-metadata';
Note: This does not currently support Hashes.
Legacy Browser Support
In general, Cascade fully supports older browsers, including Internet Explorer 9+. However, Arrays and Hashes are one area where some special consideration must be made.
First off, Observable Hashes are not supported. Their functionality can be emulated easily with ObservableArrays and a regular Hash object.
Secondly, Observable Arrays work slightly differently in Internet Explorer. In modern browsers, we can simply write to any index and it will be detected.
viewModel.list[0] = 'value';
However, in Internet Explorer, we must use an explicit setter method.
ObserableArray<T>.set(index: number, value: T): void;
Which in practice would look like:
viewModel.list.set(0, 'value');
However, TypeScript will complain that the set
method doesn't exist on Array
. So, we can update our View Model to use IArray<T>
instead of T[]
or Array<T>
. This interface can be imported from Cascade.
class ViewModel {
@array list: IArray<string>;
@hash map: IHash<string>;
}