Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何告诉TypeScript对象中存在可选属性并已设置?_Typescript - Fatal编程技术网

如何告诉TypeScript对象中存在可选属性并已设置?

如何告诉TypeScript对象中存在可选属性并已设置?,typescript,Typescript,我有以下代码: 接口优先 { 属性a:字符串; } //这里propertyA是可选的 //假设此接口来自外部库。 接口秒 { propertyA?:字符串; } 函数fn(参数:第一个) { // ... } //我知道这个对象可以声明为First的类型, //但我真的需要将其设置为第二种接口类型 让myVar:Second={propertyA:'some string'}; //我真的需要用这种方式打电话。 fn(myVar);//错误 if(myVar.hasOwnProperty('p

我有以下代码:

接口优先
{
属性a:字符串;
}
//这里propertyA是可选的
//假设此接口来自外部库。
接口秒
{
propertyA?:字符串;
}
函数fn(参数:第一个)
{
// ...
}
//我知道这个对象可以声明为First的类型,
//但我真的需要将其设置为第二种接口类型
让myVar:Second={propertyA:'some string'};
//我真的需要用这种方式打电话。
fn(myVar);//错误
if(myVar.hasOwnProperty('propertyA'))
{
fn(myVar);//仍然是相同的错误
}
if(myVar.propertyA)
{
fn(myVar);//仍然是相同的错误
}
但是类型脚本抛出错误:

类型为“Second”的参数不能分配给类型为“First”的参数。 属性“propertyA”在类型“Second”中是可选的,但在类型“First”中是必需的


那么,如何告诉TypeScript,
myVar
中的可选属性
propertyA
存在并已设置?

我不明白为什么您将其声明为type
Second
,因为它具有该属性。但是,您可以执行以下操作之一:

  • 将声明中的类型更改为
    First
    ,即
    让myVar:First={propertyA:'some string'}
  • 完全删除类型声明。然后,它将接收一个匿名类型
    {propertyA:string;}
    ,并将首先分配给
    ,即
    让myVar={propertyA:'some string'}
  • 使用显式类型转换,即
    fn(myVar)
导致此错误的原因是,假设可选属性将在其中不安全。

您可以执行以下操作:

fn(myVar as First);
并在以下情况下使用a:

function isFirst(obj: any): obj is First {
    return obj && obj.propertyA;
}

if(isFirst(myVar)) {
  fn(myVar);
}

这个问题可能更一般地是关于创建一个类型保护,告诉编译器您的值是一个新类型,其中所述字段不是可选的,而是必需的

一种方法是使用TypeScript附带的
Required
类型,该类型将所有的字段翻转为必填字段。然而,一个更现实的场景是,可能不是所有字段都被检查存在,但只有一些字段被检查存在

下面是针对这种情况的泛型类型和typeguard的示例:

    /** 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
    }
/**具有可选属性的接口*/
接口数据{
foo?:{bar?:string};
其他?:{bar?:string};
始终:{bar?:string};
}
/**用于制作所需类型的某些键的实用程序*/
类型RequiredKeys=排除和必需
/**IOPerationalData中属性“foo”的Typeguard*/
const-ensureOproperty=(数据:IOOptionalData):需要数据键=>
!!data.foo&&typeof data.foo.bar==='string'
const accessData=(数据:iooptionaldata)=>{
如果(确保财产(数据)){
console.log(data.always.bar)//始终是定义的
console.log(data.other.bar)//编译器错误:“other”可能未定义
return data.foo.bar//由于ensureToFoo,允许访问可选道具
}
console.log(data.foo.bar)//编译器错误:“foo”可能未定义
}


注意:在我的示例中,您总是可以将检查内联到if语句中,但是,由于DRY(您的类型保护可能会更复杂一些)的原因,这并不总是最佳的操作过程。

旧问题,但是在较新版本的typescript中有一个非常干净的解决方案

fn(myVar!);

如果你认真对待我的问题,也许会更容易理解。例如,如果我使用外部库,我无法更改
接口秒
的定义,但它仍然与
接口第一
兼容。问题是,由于可选属性,接口
第二
与接口
第一
不兼容。不管怎样,我介绍的3个解决方案在本例中都有效。谢谢,我知道类型保护,但它的作用有点不同,因为我不需要检查参数的类型。我有两个兼容的对象,我相信这是澄清TypeScript这一事实的有效方法。但它们不兼容<代码>{a:any}
{a?:any}
的类型不同。除了类型assert或类型guard之外,您无法为编译器澄清这一点。对于我来说,您的RequiredKeys实用程序类型没有按预期工作。这个版本做到了:
type RequiredKeys=Exclude&{[key in K]-?:Required}