是否可以注释一个函数以告知打字稿编译器检查了类属性的类型?

时间:2019-07-03 13:58:52

标签: typescript typescript-typings

下面的代码段是否可以对readText进行注释,以告诉编译器确保this.textstring而不是string | undefined

type MyResponse = {
  text: () => Promise<string>;
};

class ResponseVerfier {
  response: MyResponse;
  text?: string;

  constructor(response: MyResponse) {
    this.response = response;
  }

  async readText() {
    this.text = await this.response.text();
  }

  async verifyTextContains(value: string) {
    await this.readText();

    // I've run this.readText so I now know this.text is a string, not string | undefined
    // However I'm currently getting an error "Object is possibly 'undefined'"
    return this.text.includes(value);
  }
}

Playground link

2 个答案:

答案 0 :(得分:0)

您可以使用non-null assertion postfix operator告诉编译器“在给定的表达式中,我的操作数不能为null或未定义”

所以,如果您写:

return this.text!.includes(value);

一切正常。这是您提供的保证。

答案 1 :(得分:0)

我认为TypeScript缺少使此代码正常工作所需的几个功能,以便运行时代码相同并且编译器验证其类型安全性。第一个缺少的功能是以某种方式完成user-defined type assertions (as suggested in this GitHub issue)的方式,类似于user-defined type guards的工作方式。这样,您可以告诉编译器this.readText()将(最终)将this的类型缩小为this & {text: string}。即使具有该功能,您也需要能够返回类型声明的Promise而不是类型声明本身,这将需要诸如propagation of type predicates (as suggested in this GitHub issue)之类的东西。如果这两个都实现了,那么也许您可以做类似的事情:

// DOES NOT COMPILE, DON'T TRY THIS
async readText(): Promise<this as (this & {text: string})> {
  this.text = await this.response.text();
}

其中Promise<this as (this & {text: string})>表示readText()返回一个诺言,该诺言在解决后会将this的类型缩小到其text属性肯定是string而不仅仅是string | undefined。 las,这行不通。


使代码按原样工作而不在运行时进行任何更改的方法是使用类型断言,例如@Phillip的non-null assertion ! operator中所示的answer

如果您不介意更改代码的工作方式,那么我强烈建议将异步和同步代码分成两个完全不同的结构,并让异步代码返回完全配置的同步对象,例如:

type MyResponse = {
  text: () => Promise<string>;
};

// all async code should be in here
class AsyncResponseVerifier {
  constructor(public response: MyResponse) {}
  async readText(): Promise<SyncResponseVerifier> {
    return new SyncResponseVerifier(await this.response.text());
  }
}

// all code in here should be synchronous
class SyncResponseVerifier {
  constructor(public text: string) {}
  verifyTextContains(value: string) {
    return this.text.includes(value);
  }
}

您将像这样使用它:

// use the async thing to get the sync thing
async function doThings() {
  const asyncRV = new AsyncResponseVerifier({
    text: async () =>
      "an important forum raising awareness about serious things"
  });
  const syncRV = await asyncRV.readText();
  syncRV.verifyTextContains("rum raisin");
}

Link to code

否则,您将获得一个分裂性格的班级,该班级的某些事情应该await进行,而其他事情则不应该。即使您能弄清楚如何使编译器跟踪哪个是哪个(并且正如我在顶部所述,我认为您也无法做到),开发人员可能很难跟踪。

无论如何,希望能有所帮助。祝你好运!