我有以下代码:
interface First
{
propertyA: string;
}
// Here propertyA is optional
// Imagine that this interface came from external library.
interface Second
{
propertyA ?: string;
}
function fn(arg: First)
{
// ...
}
// I know that this object can be declared as type of First,
// but I really need set this as type of Second interface
let myVar: Second = {propertyA: 'some string'};
// I really need in this way to make the call.
fn(myVar); // Error
if(myVar.hasOwnProperty('propertyA'))
{
fn(myVar); // Still same error
}
if(myVar.propertyA)
{
fn(myVar); // Still same error
}
但TypeScript抛出错误:
"Second"类型的参数不能分配给"First"类型的参数.属性'propertyA'在类型'Second'中是可选的,但在'First'类型中是必需的.
那么,如何告诉打字稿是可选属性propertyA
的myVar
存在,并且设置?
这个问题可能更一般地是关于创建一个类型保护,该类型保护告诉编译器您的值是一个新类型,其中所述字段不是可选的,而是必填/必需的。
一种方法是使用Required
TypeScript附带的类型,该类型翻转所有字段成为必需。但是,更现实的情况是可能不是全部,而是仅检查了某些字段。
这是这种情况下的通用类型和类型保护的示例:
/** Interface with optional properties */ interface IOptionalData { foo?: { bar?: string }; other?: { bar?: string}; always: { bar?: string }; } /** Utility to make certain keys of a type required */ type RequiredKeys= Exclude & Required > /** Typeguard for property 'foo' in IOptionalData */ const ensureFooProperty = (data: IOptionalData): data is RequiredKeys => !!data.foo && typeof data.foo.bar === 'string' const accessData = (data: IOptionalData) => { if (ensureFooProperty(data)) { console.log(data.always.bar) // always is always defined console.log(data.other.bar) // COMPILER ERROR: 'other' is possibly undefined return data.foo.bar // accessing optional props is allowed due to ensureToFoo } console.log(data.foo.bar) // COMPILER ERROR: 'foo' is possibly undefined }
https://gist.github.com/elnygren/ddd28c2f0d737d8a1130da783426fea7
注意:在我的示例中,您始终可以将check内联到if语句中,但是,由于DRY,这并非总是最佳的操作方法(您的类型防护可能会更复杂)