验证打字稿中数字和枚举的联合类型

时间:2021-05-29 05:58:36

标签: typescript

我正在使用 Typescript 制作一个 SSML 构建器 npm 包。

我在打字稿中有一个函数,如下所示,可以将 Prosody 对象转换为 SSML 标签。

prosody(attributes: ProsodyAttributes, word: string){

        const {rate, volume, pitch} = attributes;

        let tag = `<prosody `;

        if(rate){

            tag += `rate="${rate}"`

        }

        if(pitch){

            tag += `pitch="${pitch}"`

        }

        if(volume){

            tag += `volume="${volume}"`

        }

        tag += `>${this._escape(word)}</prosody>`;

        this._elements.push(tag);

        return this;

    }

以下是类型。速率、音高和音量可以是数字或确定值。我为他们每个人都创建了一个枚举。我使用联合类型来满足数字和固定值。

enum Rate{
    xslow = "x-slow",
    slow = "slow",
    medium = "medium",
    fast = "fast",
    xfast = "x-fast"
}

enum Pitch{
    xlow = "x-low",
    low = "low",
    medium = "medium",
    high = "high",
    xhigh = "x-high"
}

export enum Volume{
    silent = "silent",
    xsoft = "x-soft",
    soft = "soft",
    medium = "medium",
    loud = "loud",
    xloud = "x-loud"
}

interface ProsodyAttributes {
    rate?: Rate | number,
    pitch?: Pitch | number,
    volume?: Volume | number
}

验证函数输入参数的正确方法是什么?

我尝试过类似下面的代码:

if (typeof rate === "number"){

  if(rate < 20 || rate > 200){

    throw("attributes.rate is out of range")

  }

} else {

  if(!Object.values(Rate).includes(rate)){

    throw("attributes.rate is invalid");

  }

}

我有以下疑问:

  1. 这是正确的方法吗?
  2. 我应该首先使用枚举吗?是不是有点矫枉过正?

我必须在非打字稿项目中使用这个项目,其中速率、音调和音量的值将从请求参数中选取?

enter image description here

我设计韵律函数的方法导致类型不兼容。我该如何处理?

1 个答案:

答案 0 :(得分:1)

枚举由打字稿编译器发出。这意味着它们在运行时存在。因此,您应该从 javascript 或打字稿中执行以下操作:

prosody({ volume: Volume.loud })

如果你使用枚举,那就是要走的路。您需要避免传入该枚举的原始值。

你验证的方式也很好。


另一种可能更简单的方法是使用字符串联合。

类似于:

const rates = ["x-slow", "slow", "medium", "fast", "x-fast"] as const
type Rate = (typeof rates)[number] // "x-slow" | "slow" | "medium" | "fast" | "x-fast"

const arg = 'slow'
console.log(rates.includes(arg)) // true

现在 Raterates 数组中的项目之一。在类型化环境中,您仍然可以自动完成(尽管它比枚举稍差):

union autocomplete

说到底,这是一个见仁见智的问题,取决于您希望您的 API 是什么样子。