xenoterracide
xenoterracide

Reputation: 16837

Why is this not a function

For some reason authenticationProvider seems to be missing.

@autoinject()
export class ProviderManager implements AuthenticationManager {
   constructor( private container: Container ){
   }
    public authenticate( creds: Credentials ): Promise<Authentication> {
        var provider = creds.authenticationProvider();
        return this.container.get( provider ).authenticate( creds );
    }

}

Credentials

export interface Credentials {
    authenticationProvider(): { new(): AuthenticationManager };
}

the implementation UsernamePasswordCredentials

export class UsernamePasswordCredentials implements Credentials {

    public authenticationProvider(): {new(): AuthenticationManager} {
        return HttpBasicAuthentication;
    }

    user: String;
    pass: String;
}

AuthenticationManager

export interface AuthenticationManager {
    authenticate( creds: Credentials ): Promise<Authentication>;
}

Login

@autoinject()
export class Login {
    private log: Logger = LogManager.getLogger( Login );
    creds: UsernamePasswordCredentials;

    constructor( private am: AuthenticationManager, private router: Router ) {
    }

    public signIn(): void {
        this.log.debug( `authenticating ${ this.creds.user }` );
        this.am.authenticate( this.creds ).then( auth => {
            var route = Route.MANAGE_CONTENT;
            this.log.debug( `navigating to ${ route }` );
            var router = this.router;
            router.navigate( route );
        } ).catch( error => {
            this.log.error( error );
        } );
    }
}

Here's Chrome's stacktrace

   VM802:1 Uncaught TypeError: creds.authenticationProvider is not a function(…)(anonymous function) @ VM802:1
authenticate @ ProviderManager.ts:13
signIn @ login.ts:22evaluate @ aurelia-binding.js:1522
callSource @ aurelia-binding.js:4963
(anonymous function) @ aurelia-binding.js:4987
handleDelegatedEvent @ aurelia-binding.js:3176

Upvotes: 1

Views: 546

Answers (1)

David E
David E

Reputation: 1444

Thanks for sharing the Login code.

You're on the right lines, but it appears that this.creds was previously undefined.

The code

class Login {
    creds: UsernamePasswordCredentials;
}

just tells Typescript that it expect creds to be of type UsernamePasswordCredentials. But it does nothing to initialize the creds field... in particular, no javascript will get emitted for the line when the above gets transpiled (https://www.typescriptlang.org/play/ might be helpful to look at what the transpiler does).

That means that, in the signIn method, this.creds will be undefined.

This is similar to, say, in C#, where if you don't initialize a field, it defaults to null.

Whilst Typescript can catch a lot of things, it cannot (always) catch when a variable has an undefined/null value at run-time, just as a statically typed language like C# can still end up generating compiled code which triggers null reference exceptions.

EDIT: Ahh, my apologies. Had creds been undefined, you would have received a ReferenceError: creds is not defined. The TypeError should have made clear creds was populated elsewhere, but of the wrong type.

Upvotes: 1

Related Questions