温馨提示:本文翻译自stackoverflow.com,查看原文请点击:其他 - Is it possible to annotate a function to tell the typescript complier that is has checked the type o
typescript typescript-typings

其他 - 是否可以注释一个函数来告诉已检查类型的打字机编译器

发布于 2020-03-27 10:48:57

我下面的代码片段是有可能注释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);
  }
}

游乐场链接

查看更多

查看更多

提问者
Henry Munro
被浏览
168
jcalz 2019-07-04 00:20

I think TypeScript is missing several features that you'd need to get this code to work so that the runtime code is the same and the compiler verifies its type safety. The first missing feature is some way to do user-defined type assertions (as suggested in this GitHub issue) in a way similar to how user-defined type guards work already. That way you could tell the compiler that this.readText() will (eventually) narrow the type of this to this & {text: string}. Even with that feature, you'd need to be able to return a Promise of the type assertion instead of the type assertion itself, which would require some thing like propagation of type predicates (as suggested in this GitHub issue). If both of those were implemented, then maybe you could do something like:

// 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 | undefinedlas,这行不通。


使代码按原样工作而不在运行时进行任何更改的方法是使用类型声明,例如@Phillip的answer中所示非null声明!运算符

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

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");
}

链接到代码

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

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