Assertion functions are pretty useful when they're applied to classes, and there's some cool stuff you can do. Here we've got an SDK


export class SDK {

constructor(public loggedInUserId?: string) {}

createPost(title: string) {

this.assertUserIsLoggedIn()

createPost(this.loggedInUserId, title)

}

assertUserIsLoggedIn() {

if (this.loggedInUserId) {

throw new Error("User is not logged in")

}

}

}


It's kind of like if you imagine the back ends at a center point where you invoke class and you've got all your methods and stuff.

And here we've got a loggedInUserId and this can either be string or it can be undefined. When it's undefined it means the user isn't logged in and so there might be still anonymous things they can do.

But inside createPost we want to assert that the user is logged in and there we're going to use. the user ID. But the issue here is that we've got string or undefined in for the first argument of the call to createPost which is not good because actually we need string and really we've asserted that the logged in user ID exists.

So we should just be able to get this going. But we haven't told TypeScript that this.loggedInUserId is defined. If we were to move the if statement in our assertion to be inside createPost here then it would work.


export class SDK {

constructor(public loggedInUserId?: string) {}

createPost(title: string) {

this.assertUserIsLoggedIn()

if (this.loggedInUserId) {

throw new Error("User is not logged in")

}

createPost(this.loggedInUserId, title)

}

assertUserIsLoggedIn() {}

}


But how do we get this. kind of inference working? Well we can return asserts this is this &. Which means we are saying assertUserIsLoggedIn is an assertion function now and we're saying that this is this and something else and we can add loggedInUserId: string


assertUserIsLoggedIn(): asserts this is this & {

loggedInUserId: string

} {

if (this.loggedInUserId) {

throw new Error("User is not logged in")

}

}


What this does is it basically just adds an intersection to the class. and matches them both together and loggedInUserId: string wins. So we get the string inside the SDK and now this.loggedInUserId is typed string.

We could probably do even something more in here. We could say wow which is a Boolean. And then use this.wow in createPost


export class SDK {

constructor(public loggedInUserId?: string) {}

createPost(title: string) {

this.assertUserIsLoggedIn()

createPost(this.loggedInUserId, title)

this.wow

}

assertUserIsLoggedIn(): asserts this is this & {

loggedInUserId: string

wow: boolean

} {

if (this.loggedInUserId) {

throw new Error("User is not logged in")

}

}

}


So assertion functions are pretty useful. We do need to make sure that you check everything there. Like this.wow Boolean is technically unsafe.

But, it does give you a lot of flexibility and it means you can use it in a lot more of a reusable way.