【问题标题】:TypeScript type declaration for "member should not exist on this type"?“此类型上不应存在成员”的 TypeScript 类型声明?
【发布时间】:2020-10-19 21:32:26
【问题描述】:

TypeScript 记录类型中是否有办法断言该类型不得包含具有特定名称的属性?

用例是我们在运行时使用特定属性的存在来区分实现特定接口的对象与用于指定命名参数的属性包。

例如:TS playground link

interface Foo {
  readonly bar: string;
}
function f(arg: Foo | {foo: Foo}) {
  // get a Foo instance, either as the argument or as a named arg
  const foo: Foo = 'foo' in arg ? arg.foo : arg;
  return foo.bar;
}

我们想警告Foo 接口的实现者,他们的类型不能有一个名为foo 的属性。例如,我们希望这段代码导致编译错误:

class MyFoo1 implements Foo {
  foo: Foo = { get bar() { return 'abc'; } }; // wanted: compile error here
  get bar() { return this.foo.bar; }
}
class MyFoo2 implements Foo {
  foo: string = 'bar'; // wanted: compile error here
  get bar() { return this.foo; }
}
// no compiler errors expected from this class
class MyFoo3 implements Foo {
  get bar() { return 'hello'; }
}

我们可以这样做吗?

我考虑过的可能解决方案是:

  1. never - 这个会产生错误,但它也声称这个属性确实存在,这似乎是错误的。
interface Foo {
  foo: never;
  bar: string;
}
  1. undefined - 这似乎更接近我们想要的,但是当它从不存在时它不会仍然显示在 IDE 自动完成中吗?
interface Foo {
  foo?: undefined;
  bar: string;
}
  1. 条件类型 - 这似乎是最有前途的,但我不确定如何制作非泛型条件类型,以便调用者可以说class MyFoo2 implements Foo 而不是class MyFoo2 implements Foo<SomethingElse>

【问题讨论】:

    标签: typescript


    【解决方案1】:

    你想要的技巧是:

    interface Foo {
      foo?: never
      readonly bar: string;
    }
    

    这告诉 typescript foo 要么必须被省略,要么必须具有 never 的类型,这是 从不 允许的。这减少了它必须被省略的事实。

    Playground


    请注意,我确实必须稍微更改您的运行时代码才能编译它。

    const aFoo: Foo = ('foo' in arg && arg.foo) ? arg.foo : arg;
    

    Typescript 不够聪明,无法推断出联合的分支,因为在运行时很难区分省略的 prop 和值为 undefined 的 prop。通过强制它检查arg.foo 是否具有真实值,它就知道arg 必须是{ foo: Foo } 类型。

    【讨论】:

      猜你喜欢
      • 2017-12-31
      • 1970-01-01
      • 1970-01-01
      • 2019-04-12
      • 2021-12-31
      • 2021-12-18
      • 2020-11-29
      • 1970-01-01
      • 2016-12-23
      相关资源
      最近更新 更多