dragonmnl dragonmnl - 1 month ago 14
TypeScript Question

How to set optional class parameters in Angular 2-Typescript?

I know in Typescript optional parameters can be marked by question mark

However the only way I found to actually instantiate the class with new keyboard.

The thing is that based on Angular 2's starter "hero" tutorial classes are not instantiated via new keyword and as far as I understood that's internally done by Angular.

For example I have this code:

models/users.ts

export class User {
id: number;
name: string; // I want this to be optional
}


models/mock-users.ts

import {User} from './user';

export var USERS: User[] = [
{
id: 1
// no name (I wanted it to be optional for user with id 1)
},
{
id: 2,
name: "User 2"
},
]


services/user.service.ts

import {Injectable} from 'angular2/core';
import {USERS} from './../models/mock-users';

@Injectable()
export class UserService {
getUsers() {
return Promise.resolve(USERS);
}
}


views/my-component.component.ts

// imports here...

@Component({
// ...
})

export class MyComponent {
constructor(private _userService: UserService) { }

getUsers() {
this._userService.getUsers().then(users => console.log(users));
}
}

Answer

In your case, it might be more convenient to use an interface for User instead.

export interface User {
    id: number;
    name?: string; // interfaces allow fields to be optional
}

I use interfaces when I want to define the 'shape' of an object, classes when I need to add behavior (methods). If all you need is to move data around, I'd use an interface.

If you do need a class, then the syntax for creating instances of Users in mock-users.ts should be a bit different. Firstly, there's no "optional class fields" in TypeScript. Any field can be not set/'undefined', so it doesn't make sense mark a field optional. You can instantiate a class with the new keyword - the downside is that you need to write a constructor to set field values or assign the instance to a variable and set fields. But there's nothing wrong with using the new keyword, especially for test objects.

You can also instantiate an object with an object literal as you've done in mock-users.ts - you need to be more explicit by adding a cast.

export var USERS: User[] = [
    <User> { // explicit cast to let the TypeScript compiler know you know what you're doing
       id: 1
       // no name (I wanted it to be optional for user with id 1)
    },
    {
       id: 2,
       name: "User 2"
    },        
]

Without the cast, the TypeScript compiler will produce an error. This is by design to catch a mistakes. If you want to know more about the (interesting) reasons, here's a related detailed discussion on some of the thinking behind the type checking:

Comments