![](/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.