Within my Angular2 project, I have defined an Interface called GridMetadata
:
grid-metadata.ts
export interface GridMetadata {
activity: string;
createdAt: object;
totalReps: number;
updatedAt: object;
}
In my Service, there is a public method named create
. This method expects an argument that should be an Object with one property - activity
holding a String value like { activity: 'Push-Ups' }
. You can find this implementation at the end of GridService
:
grid.service.ts
import { Injectable } from '@angular/core';
import {
AngularFireDatabase,
FirebaseListObservable
} from 'angularfire2/database';
import * as firebase from 'firebase/app';
import { AuthService } from './auth.service';
import { GridMetadata } from './grid-metadata';
@Injectable()
export class GridService {
private gridMetadata: FirebaseListObservable<any>;
constructor(
private afDb: AngularFireDatabase,
private authService: AuthService
) {
this.init();
}
private init(): void {
this.gridMetadata = this.afDb.list('gridMetadata');
}
create(metadata: GridMetadata): Promise<any> {
function isGridMetadata(obj: any): obj is GridMetadata {
return typeof obj.activity === 'string' &&
typeof obj.createdAt === 'object' &&
typeof obj.totalReps === 'number' &&
typeof obj.updatedAt === 'object' ?
true :
false;
}
return new Promise((resolve, reject) => {
if (this.authService.isAuthenticated === false) {
return reject(new Error('Cannot create new grid without authentication.'));
}
let key: string = this.gridMetadata.push(undefined).key;
let uri: string = [this.authService.currentUserId, key].join('/');
metadata.createdAt = firebase.database.ServerValue.TIMESTAMP;
metadata.totalReps = 0;
metadata.updatedAt = firebase.database.ServerValue.TIMESTAMP;
if (isGridMetadata(metadata) === false) {
return reject(new TypeError('`metadata` does not match the signature of the `GridMetadata` interface.'));
}
this.gridMetadata.update(uri, metadata)
.then(() => {
resolve();
})
.catch((error) => {
reject(new Error(error.message));
});
});
}
}
Query 1
It's noted that the argument required by the create
method doesn't completely align with the GridMetadata
interface. Despite this mismatch, no errors are triggered during either compile-time or runtime. Why do you think this happens?
I might have misunderstood due to being new to TypeScript.
Query 2
You believe there should be an error in question 1; while it could be fixed easily, your curiosity lies in why no error occurs. You further elaborate on how you modify the metadata
Object to adhere to the GridMetadata
interface before rejecting the Promise if they don't match.
Is there a more efficient way to verify that createdAt
and updatedAt
meet the criteria of { .sv: 'timestamp' }
, other than using the current if
statement?
Query 3
Lastly, for convenience, are there methods available to programmatically establish a User Defined Type Guard based on an Interface?
Perhaps due to the Interface not being viewed as an object by TypeScript, it may not be feasible to dynamically work with it within a function. For instance, extracting properties such as activity, createdAt, ...
and their respective values string, object, ...
to iterate through and validate within the guard.
Although three queries are presented here, the primary focus is on Q2, as Q1 likely has a straightforward answer, while Q3 presents an additional challenge. Responses addressing solely Q2 are encouraged, and your assistance is greatly valued!