typescript 如果第一个参数属于特定类型,则必须定义可选的第二个参数

lrl1mhuk  于 2023-01-10  发布在  TypeScript
关注(0)|答案(2)|浏览(199)

我有一个函数可以被调用为

myFunc("")
myFunc({}, {}) // two different objects

它也可以被称为

myFunc("", {})

在这种情况下,第二个参数被简单地忽略。
如果第一个参数是obj而不是字符串,我希望防止在没有第二个参数的情况下调用它

myFunc({}) // should type error

我是这样实现的

type SomeType = { name: string }
type SomeOtherType = { config: number }

function myFunc(firstArg: string | SomeType, secondArg?: SomeOtherType): number {
  if (typeof firstArg === "string") {
    return doStringStuff(firstArg)
  }
  if (secondArg === undefined) {
    throw new Error('secondArg must be defined when firstArg is SomeType')
  }
  return doObjStuff(firstArg, secondArg)
}

(其中doStringStuff()doObjStuff()都返回数字),但是有没有更好的方法呢?在类型级别?

h43kikqp

h43kikqp1#

看起来函数重载在这里起作用了,甚至对于变量参数计数(沙箱)也令人惊讶:

function myFunc(p1: string): void;
function myFunc(p1: object, p2: object): void;
function myFunc(p1: string | object, p2: object | null = null): void { }

myFunc(''); // OK
myFunc({}, {}); // OK
myFunc({}); // Error: Argument of type '{}' is not assignable to parameter of type 'string'.
myFunc('', {}); // Error: Argument of type 'string' is not assignable to parameter of type 'object'.
myFunc({}, ''); // Error: Argument of type 'string' is not assignable to parameter of type 'object'.
myFunc('', ''); // Error: Argument of type 'string' is not assignable to parameter of type 'object'.
ttvkxqim

ttvkxqim2#

可以使用重载来确保在TypeScript中不能使用stringSomeTye进行调用:

function myFunc(firstArg: string): void
function myFunc(firstArg: SomeType, secondArg: SomeOtherType): void
function myFunc(firstArg: string | SomeType, secondArg?: SomeOtherType) {
  if (typeof firstArg === "string") {
    return doStringStuff(firstArg)
  }
  if (secondArg === undefined) {
    throw new Error('secondArg must be defined when firstArg is SomeType')
  }
  return doTypeStuff(firstArg, secondArg)
}

myFunc("", { name : ""}) // error
myFunc("") // ok

您还可以在rest参数中使用元组的并集来帮助TypeScript理解参数之间的关系:

function myFunc(...{ 0:firstArg, 1:secondArg, length }: 
  | [firstArg: string]
  | [firstArg: SomeType, secondArg: SomeOtherType]) {
  if (length === 1) {
    return doStringStuff(firstArg)
  }
  return doTypeStuff(firstArg, secondArg)
}

myFunc("", { name : ""}) // error
myFunc("") // ok

Playground链接
元组的并集在调用点的作用类似于重载,因此调用方不会暴露给元组

相关问题