我尝试在函数中的对象字段上使用类型断言,然后使用返回对象(在函数中断言)。
这里有一个例子:
interface MyInterface {
abc: string;
}
type Abc = "A" | "B";
function assertAbc(v: string): asserts v is Abc {
if (!["A", "B"].includes(v)) {
throw Error();
}
};
const needAbc = (_: Abc) => true;
const shouldBeWithAbcType = () => {
const myObj: MyInterface = { abc: "A" };
// Everything that come after this should be an object with abc as type
assertAbc(myObj.abc);
// this work as intended, abc is of type Abc
needAbc(myObj.abc);
// Return the object
return myObj;
}
const c = shouldBeWithAbcType();
// c.abc is a string, so this doesn't work, why ?
needAbc(c.abc);
为什么
needAbc(c.abc)
不起作用?
带有示例的 ts 游乐场这里
相同的示例但没有对象(返回 Abc 类型)也可以。
您可以使用Type Guards。我认为
asserts
关键字是多余的。此外,类型保护函数必须返回 boolean
指示输入是否属于您期望的类型。
function isAbc(v: string): v is Abc {
if (!["A", "B"].includes(v)) {
return false;
}
return true;
}
为什么?我猜是因为编译器不够聪明,无法在某个函数内对某个对象的字段进行某种类型断言,超出该函数的范围,从该点开始,该对象的任何地方都会发生这种情况。从技术上讲,我猜它可以,但技术上会很困难,但事实并非如此。 docs 明确指出该断言仅适用于当前范围:
TypeScript 3.7 引入了一个称为“断言签名”的新概念,它对这些断言函数进行建模。第一种类型的断言签名模拟了 Node 断言函数的工作方式。它确保所检查的任何条件对于包含范围的其余部分都必须为真。
因此,断言不仅不会在函数之外进行,甚至不会在条件或 for 循环范围之外进行。
如果您希望它工作,您需要在“shouldBeWithAbcType”外部显式定义您想要的接口,然后告诉编译器这就是“shouldBeWithAbcType”返回的内容,而不是依赖于编译器推断的类型(即“MyInterface”)。示例:
interface MyInterface {
abc: string;
}
interface MyStrictInterface {
abc: Abc;
}
type Abc = "A" | "B";
function assertAbc(v: unknown): asserts v is Abc {
if(typeof(v) !== 'string') throw new Error()
if (!["A", "B"].includes(v)) {
throw Error();
}
};
function assertAbcObject(v: unknown): asserts v is MyStrictInterface {
if(!v || typeof(v) !== 'object' || !('abc' in v)) throw new Error();
assertAbc(v.abc)
};
const needAbc = (_: Abc) => true;
const shouldBeWithAbcType = () => {
const myObj: MyInterface = { abc: "A" };
assertAbcObject(myObj)
return myObj;
}
const c = shouldBeWithAbcType();
// Works
needAbc(c.abc);