我想知道是否有一种方法可以指定对象文字的类型。
例如,如何解析此代码并分配一个B
字面意思是A
多变的:
interface A {
a: string;
}
interface B extends A {
b: string
}
const a: A = {
a: "",
b: ""
};
B
is an A
,所以我希望能够分配一个B
其中一个A
是期待。但是,编译器没有足够的上下文来确定我正在传递一个B
而不是非法的A
,所以我需要指定它。
我不想只是让上面的代码编译,我特别想要我的意图“我正在分配一个B
to an A
”被传达给编译器。我想要具有类型安全性B
对象字面量,所以如果B
例如,获取其他属性,这应该无法再次编译。
我偶然发现这个帖子 https://stackoverflow.com/questions/19456105/how-can-i-specify-a-typed-object-literal-in-typescript当搜索这个时。一种选择是定义一个恒等函数:
const is = <T>(x: T): T => x;
const a: A = is<B>({
a: "",
b: ""
});
这并不理想,因为它会为了转译后不相关的东西而运行代码。另一种选择是使用第二个变量,如下所示:
const b: B = {
a: "",
b: ""
};
const a: A = b;
出于同样的原因,它也不理想,它是用于 TypeScript 检查的代码。
@jcalz 的建议:
interface A {
a: string;
[k: string]: unknown; // any other property is fine
}
当我想要时,这允许任何多余的属性通过A
及其要传递的子类型。A
的封闭性不是问题,我只是无法告诉编译器我正在传递一个B
其中一个A
是期待。
Turn off --suppressExcessPropertyErrors compiler option
我想抑制多余的属性,问题是我无法告诉编译器这些不是多余的属性,它们是正确子类型的属性。
是否有与文字类型声明等效的东西? TypeScript 是否存在阻止此类构造存在的基本设计?
在 Kotlin 这样的语言中,这是微不足道的:
val a: A = B()
您可以分别声明变量的类型和运行时对象的类型(必须是相同类型或子类型)。
如果这是一个XY问题 https://en.wikipedia.org/wiki/XY_problem,我最初试图解决的问题如下所示:
const foo = (): A => {
if (/* condition */) {
/* some setup.. */
return {
a: "",
b: ""
}
} else {
return {
a: ""
}
}
}
这不会编译,因为第一个return
不是明确的A
,它的目的是成为B
which is an A
,但我无法将其指定为B
而不诉诸我上面提到的解决方法之一。我想要看起来像的东西
return {
a: "",
b: ""
}: B
// or
return: B {
a: "",
b: ""
}
// or
return {
a: "",
b: ""
} is B
不用说都会那样进行as B
类型断言不是我在这里寻找的。我不想绕过类型系统,我只是想帮助编译器检查我的对象文字是否为指定类型。这个问题也适用于参数:
const foo = (a: A) => {};
foo({ a: "", b: "" })
这失败了,因为我无法告诉编译器我正在传递一个B
,它认为我正在使用多余的属性。只有当我使用额外的变量时它才有效,如下所示:
const b: B = { a: "", b: "" };
foo(b)