打字稿缩小到相同类型缩小到永不

时间:2020-07-27 17:11:04

标签: typescript type-narrowing

我遇到了这个打字稿错误

Property 'id' does not exist on type 'never'.

我在这里制作了一个简化的示例(code sandbox here

interface Get {
  id: number;
}
interface Delete {
  id: number;
}

const isGet = (narrowMe: Get | Delete, narrowBy: string): narrowMe is Get =>
  narrowBy === "GET";
const isDel = (narrowMe: Get | Delete, narrowBy: string): narrowMe is Delete =>
  narrowBy === "DELETE";

const foo = (narrowMe: Get | Delete, narrowBy: string) => {
  if (isGet(narrowMe, narrowBy)) {
    return narrowMe.id;
  }
  if (isDel(narrowMe, narrowBy)) {
    return narrowMe.id; // error happens here
  }
};

真正的代码更加复杂,但是从本质上讲,我认为问题在于上面的两个接口是相同的。如果我在Get界面中添加了一个假字段,以使其与众不同,那么该错误就会消失。我正在努力寻找有关此处发生的情况以及如何解决或解决它的文档。添加伪字段是很麻烦的,除非没有其他方法,否则我真的不想将GetDelete合并为共享类型。

2 个答案:

答案 0 :(得分:0)

GetDelete接口是一回事。 TypeScript有一种称为鸭子类型的内容,因此在检查narrowMe是否符合Get接口之后,TS知道它也符合Delete接口,因此第二个if是永远不可能。诸如此类的事情通常可以通过判别来解决:

interface Get {
  type: 'get';
  id: number;
}
interface Delete {
  type: 'delete';
  id: number;
}

我同意它看起来确实很黑,但这只是TypeScript类型系统的本质。如果两个接口相同,则它们描述相同的可能对象集。它们的名称无关紧要,您必须以其他方式对其进行区分。

interface Get {
  type: 'get';
  id: number;
}
interface Delete {
  type: 'delete';
  id: number;
}

const isGet = (narrowMe: Get | Delete): narrowMe is Get =>
  narrowMe.type === "get";
const isDel = (narrowMe: Get | Delete): narrowMe is Delete =>
  narrowMe.type === "delete";

const foo = (narrowMe: Get | Delete, narrowBy: string) => {
  if (isGet(narrowMe)) {
    return narrowMe.id;
  } else if (isDel(narrowMe)) {
    return narrowMe.id; // no error, narrowMe is of type Delete
  }
};

答案 1 :(得分:0)

问题在于,这种使用类型保护的方式不是他们想要的,因此会以意外的方式表现。

最简单的解决方案是将您的逻辑不基于类型防护,而是基于arrowBy变量:

model = Sequential()
model.add(LSTM(units = 100, return_sequences = True))
model.add(Dropout(0.2))

model.add(LSTM(units=1000 , return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(units=1000 , return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(units=100))
model.add(Dropout(0.2))
model.add(Dense(units=1 ))
model.compile(optimizer=opt, loss='mean_squared_error' , metrics=[tf.keras.metrics.RootMeanSquaredError()])

Playground