如何在TypeScript中重载可选布尔值

如何在TypeScript中重载可选布尔值,typescript,Typescript,我试图推断一些使用组合框组件的类型 基本上,给定类型T,选项应该是T[],onChange处理程序应该是(值:T)=>void。但是,如果isMulti标志为true,则onChange应为(值:T[])=>void。我只是不确定如何配置重载类型以使其正常工作: 类型选项={ 选项:T[] } & ({ isMulti?:错误 onChange:(值:T)=>void } | { 伊斯穆蒂:是的 onChange:(值:T[])=>void }) 接口选项{ 值:字符串, } 常数a:选项={

我试图推断一些使用组合框组件的类型

基本上,给定类型
T
,选项应该是
T[]
,onChange处理程序应该是
(值:T)=>void
。但是,如果
isMulti
标志为true,则onChange应为
(值:T[])=>void
。我只是不确定如何配置重载类型以使其正常工作:

类型选项={
选项:T[]
} & ({
isMulti?:错误
onChange:(值:T)=>void
} | {
伊斯穆蒂:是的
onChange:(值:T[])=>void
})
接口选项{
值:字符串,
}
常数a:选项={
//伊斯穆蒂:错,
选项:[{
值:“abc”,
}],
onChange:(值)=>console.log(值)
}

基本上,问题是如果未定义
isMulti
,那么onChange中的值就是
any

参数“value”隐式具有“any”类型


有什么方法可以做到这一点,或者我需要将
isMulti
设置为必需的吗?

结果表明,我们必须在
onChange
方法中添加额外的泛型,并带有约束:

A型={
伊斯穆蒂:错,
onChange:(值:T)=>任意
}
B类={
伊斯穆蒂:是的,
onChange:(值:T[])=>any
}
C类={
onChange:(值:T)=>任意
}
//功劳归于提香·塞尔尼科娃·德拉戈米尔
//https://stackoverflow.com/questions/65805600/struggling-with-building-a-type-in-ts#answer-65805753
类型UnionKeys=T扩展T?基特:永远不会;
类型为StrictUnionHelper=
T扩展任何
? T&Partial:从不;
类型StrictUnion=StrictUnionHelper

键入Unions=StrictUnion

我可能有一个解决方法,尽管我不知道这是否是最好的解决方案。我为每个场景尝试了显式类型,并定义了一个重载函数来传递对象(尽管我希望这项工作没有不切实际的函数):

接口选项{
值:字符串,
}
//默认选项
类型选项={
选项:T[]
}
//isMulti未定义
U型={
onChange:(值:T)=>void
}
//isMulti是假的
F型={
伊斯穆蒂:错
}&U
//isMulti是真的
类型M={
伊斯穆蒂:是的
onChange:(值:T[])=>void
}
//用于确定给定参数的重载
函数getOptions(options:options&M):选项类型;
函数getOptions(options:options&U):选项类型;
函数getOptions(options:options&F):选项类型;
函数getOptions(选项:任意){
返回选项;
}
常数a=getOptions({
//伊斯穆蒂:错,
选项:[{
值:“abc”,
}],
onChange:(值)=>console.log(值)
})
这正如我所希望的那样有效,但似乎还是有些过分,例如,我不确定这是否适用于JSX/React组件的道具


在typescript上查看()

有趣。我想知道这是否可行。据我所知,TypeScript只是编译成JavaScript。任何类型、接口等仅用于编译期间的类型检查目的。但在我看来,您试图在这里捕获您的类型中的一些运行时行为。如果
a.isMulti
之后将在其他地方更改,您实际期望会发生什么?我想TypeScript将无法检查这一点。发出的JavaScript代码将运行,它将根本不知道您最初的TypeScript构造;使用重载是非常常见的做法。我只是想知道如何让它作为一种类型使用
undefined
。注意:在typescript中,您可以将isMulti设置为true或false,并且onChange函数键入正确。在tsconfig中设置
“strictNullChecks”:true可以完成此任务。当它为false时,
isMulti:true
isMulti:false
都可以未定义地分配。默认情况下,TypeScript上的strictNullChecks处于启用状态Playground@bozdoz我已经更新了我的答案,请看一下,我相信这就是你在寻找的问题,因为我想知道变量
a
定义中的值类型,我看到你在这里键入了
any
。然而,这是一个巧妙的解决方案。没有想到要让
推断
为我工作。感谢你的观点;但是,我需要
onChange
了解同级
选项
类型和
isMulti
类型。令人惊讶的是,似乎没有一个好的方法来实现这一点。这可以通过额外的功能来实现。你同意函数开销吗?我试着像你的例子那样分离接口,我已经发布了一个解决方案。看一看,希望你能改进它。:)第二个解决方案是数量惊人的“把戏”,我不明白。onChange:(value:T)
特别奇怪。也会使
onChange
函数无效:尝试返回
value.value
value.length
而不是
value
:应该能够执行其中一项操作,但因为它的类型为
T
,所以两者都不起作用。@bozdoz我的坏消息。但它很容易修复。我做了一个小的更新,帮助你理解这个技巧。此外,我还向generic添加了常量,以使其按您的预期工作,您的解决方案非常好。只需在函数声明中添加
typebase=Options&(F | U | M)
基本类型,而不是
any
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)
})