我有以下代码:
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'类型中是必需的。
那么,如何告诉TypeScript propertyA
中的可选属性myVar
是否存在且已设置?
答案 0 :(得分:3)
这个问题可能更普遍地是关于创建一个类型防护,该类型防护告诉编译器您的值是一个新类型,其中所述字段不是可选字段,而是必填字段/必填字段。
一种方法是使用TypeScript附带的Required<T>
类型,该类型翻转所有字段为必填字段。但是,更现实的情况是可能不是全部,而是仅检查了某些字段。
这是此类情况下的通用类型和类型保护的示例:
/** 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<T, K extends keyof T> = Exclude<T, K> & Required<Pick<T, K>>
/** Typeguard for property 'foo' in IOptionalData */
const ensureFooProperty = (data: IOptionalData): data is RequiredKeys<IOptionalData, 'foo'> =>
!!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(您的类型保护可能会更复杂),这并不总是最佳的操作方法。
答案 1 :(得分:2)
你可以这样做:
fn(myVar as First);
使用type guard作为if:
function isFirst(obj: any): obj is First {
return obj && obj.propertyA;
}
if(isFirst(myVar)) {
fn(myVar);
}
答案 2 :(得分:1)
我不明白为什么你把它声明为类型Second
,因为它有属性。但是,您可以执行以下操作之一:
First
,即let myVar: First = {propertyA: 'some string'};
{ propertyA: string; }
,并且可以分配给First
,即let myVar = {propertyA: 'some string'};
fn(<First>myVar);
引起错误是因为假设可选属性存在是不安全的。
答案 3 :(得分:0)
旧问题,但是在较新版本的打字稿中有一个非常干净的解决方案
fn(myVar!);
In Typescript, what is the ! (exclamation mark / bang) operator when dereferencing a member?