对 Typescript 多类型声明使用属性



有没有更好的方法来检查TypeScript中的现有属性而不是这个?

x = obj["prop"] || "default";

由于同时(即使在 Swagger 中)有可能获得由不同对象组成的数组,这对我来说越来越成为一个问题。

例如

let obj: {a:string, b?:string} | {a:string, c?:string};
obj = {a:"fuu", c:"baa"};
let x:string = obj.c; //err: no property "c" on possible object
let x:string = obj.c! || obj.b! || "default"; //err not possible
let x:string = obj["b"] || obj["c"] || "default"; //possible solution but looks bad for me cause the string access

有没有一个好的方法来处理我错过的这个问题?

这对你有用吗?

interface foo {
a?:string;
b?:string;
c?:string;
}
let a: foo = {a:"a", c:"c"};
console.log(a.a);

需要注意的是,TypeScript 中的对象类型不是"密封的"。 类型{a: string}的值必须具有字符串值a属性,但它可能具有各种额外的属性。 值{a: "hello", z: "goodbye"}可分配给{a: string}类型。 是的,编译器有时会警告多余的属性,以防止您意外丢弃有关此类属性的信息:

const v: { a: string } = { a: "hello", b: "goodbye" }; // error!
// ----------------------------------> ~~~~~~~~~~~~
//   Object literal may only specify known properties, 
//     and 'b' does not exist in type '{ a: string; }'

但这更像是 linter 规则,而不是类型安全检查:

const w = { a: "hello", b: "goodbye" };
const v2: { a: string } = w; // okay

编译器将只允许您使用已知有效的键索引到对象类型:

v2.a; // okay
v2.b; // error, Property 'b' does not exist on type '{ a: string; }'

但这并不意味着该键上绝对没有属性,编译器会将此类属性视为any类型,而不是类似于undefined类型的属性。


因此,联合类型{ a: string, b?: string } | { a: string, c?: string }的一个大问题是bc都不是有效的密钥。 类型{a: string, b?: string}的值可能具有任何类型的c属性,而类型{a: string, c?: string}的值可能具有任何类型的b属性。

同样,由于过多的属性检查,通常不会发生这种情况,但同样,这种检查不会强制执行类型安全,并且可以避免:

function foo(obj: { a: string, b?: string } | { a: string, c?: string }) { }
const oops = { a: "fuu", b: 123, c: "hello" }
foo(oops) // no error

您不希望foo()的实现假设obj.bstringundefined。 如果是这样,那么您可以编写obj.b?.toUpperCase()并在调用foo(oops)时收到运行时错误。 哎呀。


我在这里倾向于假设bc是相互排斥的,并明确表示:

function foo(obj: 
{ a: string, b?: string, c?: never } | 
{ a: string, b?: never, c?: string }
): string {
return obj.c || obj.b || "default"; // okay
}

因此,我们没有{a: string, b?: string}{a: string, b?: string, c?: never}never类型是没有可能值的类型。 如果你从c属性读取,你肯定会得到一个undefined值(因为你无法得到一个never值)。 因此,现在允许您检查b属性,因为联合的每个成员在b属性中都有已知的行为。 (类似的事情也适用于c属性)。

现在你可以不受惩罚地写obj.c || obj.b || "default",因为obj.cstring | undefined类型,obj.b也是,因此完整的表达式是string类型。

此显式版本意味着foo()接受已知良好的输入

foo({ a: "fuu", c: "baa" });

并拒绝之前错误的oops输入:

const oops = { a: "fuu", b: 123, c: "hello" }
foo(oops) //  error now
>游乐场链接到代码

最新更新