【问题标题】:Typescript conditional type - implement a type changing functionTypescript 条件类型 - 实现类型更改功能
【发布时间】:2019-04-14 20:59:54
【问题描述】:

我有具有属性的对象。这些属性可以是单值的,也可以是列表值的,有些属性是可选的,意味着它们可以是未定义的。下面是一些示例对象:

type A = {
   myProp: string;
   otherProp?: number;
}

type B = {
   coolProp?: boolean[];
   someProp: SomeOtherType[];
}

编辑: 现在,我实现了一个函数,它接受这样一个对象和一个属性的名称并按原样返回该属性,但有一个例外:如果该属性不是可选的并且不是一个数组,它会将该属性作为一个将原始类型作为数组类型的数组。

现在,我实现了一个函数,它接受这样一个对象和一个属性的名称,并按原样返回该属性,但有一个例外:如果该属性不是一个数组,它会将该属性作为一个数组返回,并带有原始类型为数组类型。

例如,上面类型 B 的属性不会改变,但类型 A 的 myProp: string; 会变成:myProp: string[];otherProp?: number 也将保持不变。

例如,上面类型 B 的属性不会改变,但类型 A 的 myProp: string; 将变为:myProp: string[];otherProp?: number 将变为 otherProp?: number[]

现在我想将此行为放入接口中的返回类型定义中,但我终生无法弄清楚如何使其工作。

我最好的尝试是:

getPropFromObject<O, P extends keyof O>(node: O, propName: P):
    any[] extends O[P] ? O[P] : O[P] extends undefined ? O[P] : O[P][]

但是对于像otherProp?: number;这样的单个可选道具它会失败

正确的类型定义应该是什么样子的?

【问题讨论】:

    标签: typescript conditional-types


    【解决方案1】:

    处理联合时的类型关系可能与您期望的相反。联合是其任何成员的基本类型。比如:

    type N = number | undefined extends undefined ? "Y" : "N" //No, the union does not extend a member
    type Y = undefined extends number | undefined  ? "Y" : "N" // Yes the union extends a member
    

    一开始这可能会令人惊讶,但如果你从集合的角度来考虑类型,那是有道理的。基类型是一个集合,其中包括表示子类型的所有集合(毕竟任何子类型实例也应该是基类型的一个实例)。

    所以回到你的问题,如果你想测试 undefined 是否与其他类型的属性联合,你需要写:undefined extends O[P]

    declare function getPropFromObject<O, P extends keyof O>(node: O, propName: P):
        any[] extends O[P] ? O[P] : undefined extends O[P] ? O[P] : O[P][]
    
    type A = {
        myProp: string;
        otherProp?: number;
    }
    
    getPropFromObject(null as any as A, "otherProp") // number | undefined
    getPropFromObject(null as any as A, "myProp") // string[]
    

    编辑

    问题改完后,要达到你想要的效果,可以使用distributive conditional type。这将分布在联合体上,例如number | undefined,条件类型应用于联合体的每个成员。

    type ToArray<T> = T extends unknown ? T extends undefined ? T : T[] : never;
    declare function getPropFromObject<O, P extends keyof O>(node: O, propName: P):
        any[] extends O[P] ? O[P] : ToArray<O[P]>
    
    type A = {
        myProp: string;
        otherProp?: number;
    }
    
    getPropFromObject(null as any as A, "otherProp") // number[] | undefined
    getPropFromObject(null as any as A, "myProp") // string[]
    

    【讨论】:

    • 您好,谢谢您的解释。但我意识到,我在我的问题中犯了一个错误: otherProp 当然应该是: number[] |未定义。
    • @ghost23 更改以反映需求的变化
    • 非常感谢您的帮助。但不幸的是,现在coolProp?: boolean[]; 变成了coolProp?: boolean[][]。它应该保持原样。
    猜你喜欢
    • 2020-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 2019-06-27
    • 2012-07-28
    • 2018-10-20
    • 2018-10-31
    相关资源
    最近更新 更多