Typescript 条件类型 - 实现类型更改功能
Typescript conditional type - implement a type changing function
我有带属性的对象。这些属性可以是单值的,也可以是列表值的,并且一些属性是可选的,这意味着它们可以是未定义的。所以这里有一些示例对象:
type A = {
myProp: string;
otherProp?: number;
}
type B = {
coolProp?: boolean[];
someProp: SomeOtherType[];
}
编辑:
现在,我实现了一个函数,它采用这样一个对象和 属性 的名称以及 属性 的 return 的名称,但有一个例外:如果属性 不是可选的,也不是数组,return 是 属性 作为数组,原始类型是数组类型。
现在,我实现了一个函数,它接受这样一个对象和 属性 的名称以及 属性 的 return 的名称,但有一个例外:如果属性 不是一个数组,它 return 是 属性 作为一个原始类型为数组类型的数组。
因此,例如,上面类型 B 的属性不会更改,但类型 A 的 myProp: string;
将变为:myProp: string[];
。 otherProp?: number
也会保持不变。
因此,例如,上面类型 B 的属性不会更改,但类型 A 的 myProp: string;
将变为:myProp: string[];
。 otherProp?: number
会变成 otherProp?: number[]
.
现在我想将此行为放入接口中的 return 类型定义中,但我终究无法弄清楚如何让它发挥作用。
我最好的尝试是:
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;
这样的单个可选道具它会失败
正确的类型定义是什么样的?
处理联合时的类型关系可能与您期望的相反。联合是其任何成员的基类型。例如:
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[]
我有带属性的对象。这些属性可以是单值的,也可以是列表值的,并且一些属性是可选的,这意味着它们可以是未定义的。所以这里有一些示例对象:
type A = {
myProp: string;
otherProp?: number;
}
type B = {
coolProp?: boolean[];
someProp: SomeOtherType[];
}
编辑:
现在,我实现了一个函数,它采用这样一个对象和 属性 的名称以及 属性 的 return 的名称,但有一个例外:如果属性 不是可选的,也不是数组,return 是 属性 作为数组,原始类型是数组类型。
现在,我实现了一个函数,它接受这样一个对象和 属性 的名称以及 属性 的 return 的名称,但有一个例外:如果属性 不是一个数组,它 return 是 属性 作为一个原始类型为数组类型的数组。
因此,例如,上面类型 B 的属性不会更改,但类型 A 的 myProp: string;
将变为:myProp: string[];
。 otherProp?: number
也会保持不变。
因此,例如,上面类型 B 的属性不会更改,但类型 A 的 myProp: string;
将变为:myProp: string[];
。 otherProp?: number
会变成 otherProp?: number[]
.
现在我想将此行为放入接口中的 return 类型定义中,但我终究无法弄清楚如何让它发挥作用。
我最好的尝试是:
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;
正确的类型定义是什么样的?
处理联合时的类型关系可能与您期望的相反。联合是其任何成员的基类型。例如:
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[]