扩展号码但不限于特定号码
extends number but do not restrict to a specific number
可能有人问过并回答过,但我没有找到答案 - 所以我问了。
解决方法不是很好,因为如果我想包含更多类型,那么升级就不会那么容易。
有更好的方法吗?
declare const max: <A extends number | string> (a: A) => (b: A) => A
max (2) (3) // Argument of type '3' is not assignable to parameter of type '2'
max ('a') ('b') // Argument of type '"b"' is not assignable to parameter of type '"a"'
// Possible workaround but will become clumsy if possible type to extends grow
declare const maxClumsy: {
(a: number): (b: number) => number
(a: string): (b: string) => string
}
maxClumsy (2) (3)
maxClumsy ('a') ('b')
跟进来自@matt-diamond
的评论
Keep in mind that you're passing in literals here... if the input variables are typed more broadly, you won't have an issue.
如果你不想每次都传递明确类型的变量,你可以使用这个方法。
type Num = number | string
type AsNum<T> = T extends string ? string :
T extends number ? number : never
declare const max: <T extends Num>(a: T) => (b: AsNum<T>) => AsNum<T>
max(2,4) max('2','4') // OK
max(2,'4') // Argument of type 'string' is not assignable to parameter of type 'number'
max(true,false) // Argument of type 'boolean' is not assignable to parameter of type 'string | number'
尽管它看起来确实和您的工作建议一样“笨拙”,甚至更多。
我说函数重载是解决问题的方法。对于两种类型,您的声明似乎没问题:
declare const maxClumsy: {
(a: number): (b: number) => number
(a: string): (b: string) => string
}
但是如果你真的关心 string
和 number
的重复,那么你可以通过编程构造这个类型;函数重载相当于函数类型的交集,因此我们可以使用一个distributive conditional type and the UnionToIntersection
helper from 将联合类型string | number
转换为所需的类型:
type CurriedUnion<T> = T extends any ? (a: T) => (b: T) => T : never
type UnionToIntersection<T> = (T extends any ? (a: T) => void : never) extends (a: infer U) => void ? U : never
type CurriedOverload<T> = UnionToIntersection<CurriedUnion<T>>
用法:
// type Test = ((a: string) => (b: string) => string) & ((a: number) => (b: number) => number)
type Test = CurriedOverload<string | number>
declare const coolMax: CurriedOverload<string | number>
// OK
coolMax (2) (3)
// OK
coolMax ('a') ('b')
// error
coolMax (2) ('b')
// error
coolMax ('a') (3)
请注意,当输入类型本身是联合时,像这样分布联合类型可能会导致意外结果;特别是,boolean
被定义为联合类型 true | false
,因此在那种情况下这不会执行您想要的操作。
可能有人问过并回答过,但我没有找到答案 - 所以我问了。
解决方法不是很好,因为如果我想包含更多类型,那么升级就不会那么容易。 有更好的方法吗?
declare const max: <A extends number | string> (a: A) => (b: A) => A
max (2) (3) // Argument of type '3' is not assignable to parameter of type '2'
max ('a') ('b') // Argument of type '"b"' is not assignable to parameter of type '"a"'
// Possible workaround but will become clumsy if possible type to extends grow
declare const maxClumsy: {
(a: number): (b: number) => number
(a: string): (b: string) => string
}
maxClumsy (2) (3)
maxClumsy ('a') ('b')
跟进来自@matt-diamond
的评论Keep in mind that you're passing in literals here... if the input variables are typed more broadly, you won't have an issue.
如果你不想每次都传递明确类型的变量,你可以使用这个方法。
type Num = number | string
type AsNum<T> = T extends string ? string :
T extends number ? number : never
declare const max: <T extends Num>(a: T) => (b: AsNum<T>) => AsNum<T>
max(2,4) max('2','4') // OK
max(2,'4') // Argument of type 'string' is not assignable to parameter of type 'number'
max(true,false) // Argument of type 'boolean' is not assignable to parameter of type 'string | number'
尽管它看起来确实和您的工作建议一样“笨拙”,甚至更多。
我说函数重载是解决问题的方法。对于两种类型,您的声明似乎没问题:
declare const maxClumsy: {
(a: number): (b: number) => number
(a: string): (b: string) => string
}
但是如果你真的关心 string
和 number
的重复,那么你可以通过编程构造这个类型;函数重载相当于函数类型的交集,因此我们可以使用一个distributive conditional type and the UnionToIntersection
helper from string | number
转换为所需的类型:
type CurriedUnion<T> = T extends any ? (a: T) => (b: T) => T : never
type UnionToIntersection<T> = (T extends any ? (a: T) => void : never) extends (a: infer U) => void ? U : never
type CurriedOverload<T> = UnionToIntersection<CurriedUnion<T>>
用法:
// type Test = ((a: string) => (b: string) => string) & ((a: number) => (b: number) => number)
type Test = CurriedOverload<string | number>
declare const coolMax: CurriedOverload<string | number>
// OK
coolMax (2) (3)
// OK
coolMax ('a') ('b')
// error
coolMax (2) ('b')
// error
coolMax ('a') (3)
请注意,当输入类型本身是联合时,像这样分布联合类型可能会导致意外结果;特别是,boolean
被定义为联合类型 true | false
,因此在那种情况下这不会执行您想要的操作。