使用 asserts 进行类型断言

问题

假设我们有一个类是这样的:

export function createPost(_userId: string, _title: string) {
  // do something
}

export class SDK {
  public loggedInUserId?: string;

  public constructor(userId?: string) {
    this.loggedInUserId = userId;
  }

  public createPost(title: string) {
    this.assertUserIsLoggedIn();

    // Argument of type 'string | undefined' is not assignable to parameter of type 'string'
    createPost(this.loggedInUserId, title);
  }

  private assertUserIsLoggedIn() {
    if (!this.loggedInUserId) {
      throw new Error('User is not logged in');
    }
  }
}

由于 this.loggedInUserId 的类型是string | undefined, 所以在调用createPost(this.loggedInUserId, title)的时候会报类型校验的错误, 其他经过了上面的this.assertUserIsLoggedIn();后, this.loggedInUserId已经不可能是undefined,那么我们怎么该怎么做才能通过类型校验呢? 有的同学可能说这个很容易呀,只要这样就可以了:createPost(this.loggedInUserId!, title); 但是这样是不完美的,因为加入上面的this.assertUserIsLoggedIn();在后期迭代中删掉了, 那么下面的方法仍旧不会报类型错误,这样就会出问题了。 最好的方式应该是去修改assertUserIsLoggedIn这个方法, 从而让下面的this.loggedInUserId变成非underfined

剧透预警线

解答

export function createPost(_userId: string, _title: string) {
  // do something
}

export class SDK {
  public loggedInUserId?: string;

  public constructor(userId?: string) {
    this.loggedInUserId = userId;
  }

  public createPost(title: string) {
    this.assertUserIsLoggedIn();

    createPost(this.loggedInUserId, title);
  }

  private assertUserIsLoggedIn(): asserts this is (this & {loggedInUserId: string}) {
    if (!this.loggedInUserId) {
      throw new Error('User is not logged in');
    }
  }
}

知识点