【问题标题】:typescript function overloading with different arg object signature具有不同 arg 对象签名的打字稿函数重载
【发布时间】:2021-05-26 17:59:33
【问题描述】:

我有一个函数可以接收两个不同的对象签名作为参数。我该如何输入?

fn({ a: 'a', c: 'c' })
fn({ b: 2, c: 'c' })

但是我尝试定义参数类型,TS 抱怨该类型不存在 a 和 b(只有两者都存在的 c 很好)

export type IUploadImageArgs =
    | {
            uri: string;
            type: string;
            path: string;
      }
    | {
            path: string;
            file: any;
      };

const uploadImage = async ({ file, path }: IUploadImageArgs) => {

}
// Property 'file' does not exist on type 'IUploadImageArgs'

旁注: 这是一个react native + web项目,一个抽象文件上传的函数,其中web版本接受文件本身,而native版本接受文件的本地路径。

谢谢!

【问题讨论】:

  • function fn(args:{a:string, c:string}|{b:number, c:string}) 怎么样?
  • 我试过了,我得到错误 a/b 在 args 上不存在(编辑问题以反映这一点)

标签: typescript


【解决方案1】:

就像 d2b 所说,在这种简单的情况下,您可以将参数设置为联合类型:function fn(obj: { a: string, c: string } | { b: number, c: string })

如果你有更复杂的需求,比如每组参数的返回值不同,你可以多次声明function。需要有一个单一的实现,其主体和参数可以接受任何替代方案。

function fn(obj: { a: string, c: string }): number;
function fn(obj: { b: number, c: string }): string;
function fn(obj: { a: string, c: string } | { b: number, c: string }): number | string {
  // impl
}

【讨论】:

  • 我试过了,我得到错误 a/b 在 args 上不存在(编辑问题以反映这一点)
  • 您不能解构参数对象上的属性,除非它存在于联合类型的 每个 成员上(在您的情况下,path 可以安全解构,但 @ 987654326@ 不是)。你应该做const uploadImage = (args: IUploadImageArgs) => /* ... */,然后有条件地在函数体中解构argsnarrowed its type
【解决方案2】:

一种允许您像这样直接解构联合类型的解决方案(无需首先测试联合的哪个分支)是为每个分支提供相同的属性名称,并使每个分支上的“缺失”属性可选输入undefined

type ArgType =
    | {a: string, b: number, c?: undefined}
    | {a: string, b?: undefined, c: string}

function test({a, b}: ArgType): void {
    a //: string
    b //: number | undefined
}

Playground Link

这也意味着每个非共享属性都充当联合的判别式 - 如果不这样做,您的代码将接受像 {a: 'foo', b: 23, c: 'bar'} 这样的对象,并且不清楚正确的结果应该是什么。通过以上述方式区分并集,这个混合对象将不是一个有效的参数。

请注意,由于 Typescript 在进行控制流类型缩小时不会跟踪不同变量之间的关系,因此如果您确实解构了 {a, b, c},那么测试以查看 b 是否未定义不会将 c 缩小为类型为string,反之亦然。为此,您应该编写arg: ArgType 并在测试它是联合的哪个分支后对其进行解构。

【讨论】:

    【解决方案3】:

    虽然下面的答案涵盖了一些有用的用例,但对于我的用例来说,唯一的解决方案似乎是实现两个不同的函数并根据当前平台调用它们,而不是让 react native 为我管理文件导入。

    p>

    感谢@joonas 和@kaya3 的回答!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-17
      • 1970-01-01
      • 2023-03-10
      • 2020-05-20
      相关资源
      最近更新 更多