"member should not exist on this type"的打字稿类型声明 ?



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

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

例如:TS游乐场链接

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>

你想要的技巧是:

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

这个命令告诉typescript,foo必须被省略,或者它必须具有never的类型,这是从不允许的。这就减少了必须省略它的事实。

游乐场


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

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

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

最新更新