【问题标题】:How to access "type" properties of an optional property?如何访问可选属性的“类型”属性?
【发布时间】:2019-11-08 18:31:07
【问题描述】:

参见下面的代码 sn-p:

interface MyObj {
  myOptionalProp: MyOptionalPropObj;  // NOT OPTIONAL
} 

interface MyOptionalPropObj {
  myProp1: SomeType;
  myProp2?: SomeType;
}

type Test1 = MyObj['myOptionalProp']['myProp1'];  // Works
type Test2 = MyObj['myOptionalProp']['myProp2'];  // Works

如果myOptionalProp 不是可选的,则访问MyObj 中要分配给Test1Test2 的嵌套属性可以正常工作。

但是。一旦myOptionalProp 是可选的:

interface MyObj {
  myOptionalProp?: MyOptionalPropObj; // OPTIONAL
} 

interface MyOptionalPropObj {
  myProp1: SomeType;
  myProp2?: SomeType;
}

type Test1 = MyObj['myOptionalProp']['myProp1'];  // Doesn't work
type Test2 = MyObj['myOptionalProp']['myProp2'];  // Doesn't work

TypeScript 抛出此错误:

Property 'myProp1' does not exist on type 'MyOptionalPropObj | undefined'.ts(2339)

有没有办法在访问类型时进行断言?类似于

myObj.myOptionalProp!.myProp1

但是对于types?


此示例中的 MyObj 类型是在我们的情况下自动生成的,特别是 GraphQL 代码生成器,我们无法控制它的结构。我们本可以直接使用 SomeType 类型,但目前这不是一个选项。

自动生成的类型示例是:

export type TestQuery = (
  { __typename?: 'Query' }
  & { profile: Maybe<(
    { __typename?: 'Profile' }
    & Pick<Profile, 'id' | 'name' | 'updatedAt' | 'createdAt'>
    & { owner: Maybe<(
      { __typename?: 'User' }
      & Pick<User, 'id' | 'displayName'>
    )>, users: Maybe<Array<(
      { __typename?: 'User' }
      & Pick<User, 'id' | 'displayName'>
    )>> }
  )> }
);

在此示例中,我们无法访问 profileowner 属性,因为所有者可以是未定义的。

TestQuery['profile']['owner'] // Doesn't work

【问题讨论】:

    标签: typescript


    【解决方案1】:

    如果一个属性是可选的,它的类型是与 undefined 联合的,因为只有联合的公共属性是可访问的,所以原始类型的所有属性都变得不可访问。

    您需要从联合中删除 undefined。预定义的条件类型Exclude 可以解决问题:

    interface MyObj {
        myOptionalProp?: MyOptionalPropObj; // OPTIONAL
    }
    
    interface MyOptionalPropObj {
        myProp1: string;
        myProp2?: number;
    }
    
    type Test1 = Exclude<MyObj['myOptionalProp'], undefined>['myProp1']; //ok
    type Test2 = Exclude<MyObj['myOptionalProp'], undefined>['myProp2'];  // ok
    

    Playground Link

    【讨论】:

    • 如果我们开始进一步挖掘,看起来这看起来很难看,但确实可以完成工作。有替代品吗?
    • 创建一些DeepRequired 类型以从所有属性中删除nullundefined?创建一些助手type KeyOf&lt;T, K extends Exclude&lt;T, null | undefined&gt;&gt; = Exclude&lt;T, null | undefined&gt;[K] ?我猜有几种方法可以简化它..
    • 谢谢!这就是我们一直在寻找的。它现在可以工作了。
    猜你喜欢
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-19
    • 2011-04-28
    相关资源
    最近更新 更多