![](/img/trans.png)
[英]How to overload function in TypeScript with optional parameters?
[英]How to overload optional boolean in TypeScript
我正在尝试推断一些使用 combobox 组件的类型。
基本上,给定一个类型T
,选项应该是T[]
,并且 onChange 处理程序应该是(value: T) => void
。 但是,如果isMulti
标志为真,那么 onChange 应该是(value: T[]) => void
。 我只是不确定如何配置重载类型以使其正常工作:
type Options<T = any> = {
options: T[]
} & ({
isMulti?: false
onChange: (value: T) => void
} | {
isMulti: true
onChange: (value: T[]) => void
})
interface Option {
value: string,
}
const a: Options<Option> = {
// isMulti: false,
options: [{
value: 'abc',
}],
onChange: (value) => console.log(value)
}
基本上问题是如果isMulti
未定义,那么 onChange 中的值是any
!
参数“值”隐含地具有“任何”类型。
有什么办法可以做到这一点,还是我需要使isMulti
必需的?
事实证明,我们必须在带有约束的onChange
方法中添加额外的泛型:
type A<T> = {
isMulti: false,
onChange: (value: T) => any
}
type B<T> = {
isMulti: true,
onChange: (value: T[]) => any
}
type C<T> = {
onChange: (value: T) => any
}
// credits goes to Titian Cernicova-Dragomir
//https://stackoverflow.com/questions/65805600/struggling-with-building-a-type-in-ts#answer-65805753
type UnionKeys<T> = T extends T ? keyof T : never;
type StrictUnionHelper<T, TAll> =
T extends any
? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
type StrictUnion<T> = StrictUnionHelper<T, T>
type Unions<T> = StrictUnion<A<T> | B<T> | C<T>>
type Options<T = any> = {
options: T[]
} & Unions<T>
interface Option {
value: string,
}
const a: Options<Option> = {
options: [{
value: 'abc',
}],
// trick is here
onChange: <T extends Option>(value: T) => {
return value
}
}
const b: Options<Option> = {
isMulti: true,
options: [{
value: 'abc',
}],
onChange: <T extends Option[]>(value: T) => {
return value
}
}
const c: Options<Option> = {
isMulti: false,
options: [{
value: 'abc',
}],
onChange: <T extends Option>(value: T) => {
return value
}
}
// error because if isMulti is false, value should be Option and not an array of Option
const d: Options<Option> = {
isMulti: false,
options: [{
value: 'abc',
}],
// should be T extends Option instead of T extends Option[]
onChange: <T extends Option[]>(value: T) => {
return value
}
}
a.onChange({ value: 'hello' }) // ok
b.onChange([{ value: 'hello' }]) // ok
c.onChange({ value: 'hello' }) // ok
c.onChange([{ value: 'hello' }]) // expected error
如果你想了解这个技巧,请阅读答案
我可能有一个解决方法,但我不知道这是否是最好的解决方案。 我为每个场景尝试了显式类型,并定义了一个重载的 function 来传递 object (尽管我希望这项工作没有不切实际的功能):
interface Option {
value: string,
}
// default Options
type Options<T = Option> = {
options: T[]
}
// isMulti is undefined
type U<T> = {
onChange: (value: T) => void
}
// isMulti is false
type F<T> = {
isMulti: false
} & U<T>
// isMulti is true
type M<T> = {
isMulti: true
onChange: (value: T[]) => void
}
// overloads for determining given parameters
function getOptions<T>(options: Options<T> & M<T>): typeof options;
function getOptions<T>(options: Options<T> & U<T>): typeof options;
function getOptions<T>(options: Options<T> & F<T>): typeof options;
function getOptions(options: any) {
return options;
}
const a = getOptions({
// isMulti: false,
options: [{
value: 'abc',
}],
onChange: (value) => console.log(value)
})
这正如我所希望的那样工作,但它似乎仍然有点矫枉过正,例如,我不确定这是否适用于 JSX/React 组件的 props。
查看 typescript 操场( 链接)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.