Just new to typescript in an angular context. Can you mark properties as optional in the example below? How would you recommend specifying a nav item has no children? With regular JS I would usually rely on a falsey value to check if the object has children
property. But in Typescript is it best practice to initialise an empty array? What about other primitive properties that may/may not have values?
import { Injectable } from '@angular/core';
export class NavItem {
key: string;
text: string;
target: string;
children: NavItem[];
}
const data: NavItem[] = [
{
key: "dashboard",
target: "dashboard",
text: "Dashboard",
children: []
},
{
key: "sales",
target: "sales",
text: "Sales"
}
];
@Injectable()
export class NavService {
getNav() {
return data;
}
}
Yeah, it's very easy to mark a property as optional, you add ?
after it:
class NavItem {
key: string;
text: string;
target: string;
children?: NavItem[];
}
Alternatively you can also use a union with null
or undefined
:
class NavItem {
key: string;
text: string;
target: string;
children: NavItem[] | undefined;
}
With that being said, you misunderstood something very important, this is wrong:
const data: NavItem[] = [
{
key: "dashboard",
target: "dashboard",
text: "Dashboard",
children: []
},
{
key: "sales",
target: "sales",
text: "Sales"
}
];
data
is not an array of NavItem
items, in order to get that you'll need to create instances of NavItem
using the new
keyword, for example:
const data: NavItem[] = [
Object.assign(new NavItem(), {
key: "dashboard",
target: "dashboard",
text: "Dashboard",
children: []
}),
Object.assign(new NavItem(), {
key: "sales",
target: "sales",
text: "Sales"
})
];
The compiler doesn't complain about doing that because typescript is based on structural subtyping and the two types share the same structure.
But it's easy to see why it's wrong by adding methods to NavItem
:
class NavItem {
key: string;
text: string;
target: string;
children?: NavItem[];
getKey() {
return this.key;
}
}
Now try this with your code:
console.log(data[0].getKey());
And you'll end up with:
Uncaught TypeError: data[0].getKey is not a function
You should even get a compilation error saying that getKey
is missing in your array items.
If you only intend to use NavItem
as data objects then it doesn't really matter, but you should just use interfaces or type aliases instead as they don't get compiled to js and you avoid redundant memory usage:
interface NavItem {
key: string;
text: string;
target: string;
children?: NavItem[];
}
After a comment from @Zze I've decided to add a simple constructor that uses the "power" of Object.assign
:
class NavItem {
key: string;
text: string;
target: string;
children?: NavItem[];
constructor(data?: NavItem) {
if (data) {
Object.assign(this, data);
}
}
}
then:
new NavItem({
key: "sales",
target: "sales",
text: "Sales"
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With