如何在不使用 as 的情况下确保 TypeScript 的 string|string[] 是 string? [英] How to ensure TypeScript that string|string[] is string without using as?

查看:31
本文介绍了如何在不使用 as 的情况下确保 TypeScript 的 string|string[] 是 string?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑
随着时间的推移,这个问题已经失去了它的有效性,因为从评论和答案中似乎可以看出这一点.尽管最初出现,但它不是这个人的骗局.

edit
Due to course of time, this question has lost its validity, as it seems from the comments and answers to this one. Despite initial appearance, it's not a dupe of this one.

我有一个通过以下签名工作的翻译功能.

I had a translator function that worked by the following signature.

getI18n(id: string) : string { ... }

我注意到输入以下内容有点乏味.

I noticed that typing the following was a bit tedious.

const titles = [
  this.util.getI18n("Donkey"),
  this.util.getI18n("Monkey"),
  ...
  this.util.getI18n("Wonkey")
];

我更喜欢使用这样的东西.

I prefer to use something like this.

const titles = this.util.getI18n(["Donkey", "Monkey", ..., "Wonkey"]);

所以我引入了一个函数,它接受带有以下签名的 stringstring[].

So I introduced a function that accepts string and string[] with the following signature.

getI18n(id: string | string[]) : string | string[] { ... }

那感觉很天才,直到我注意到我必须为愚蠢的 Typescript 解释结果是 string 而不是一些笨拙的 string 或 string array 东西,最终用这个(对于非数组翻译).

That felt genius until I noticed that I have to explain for the stupid Typescript that the result is string and not some mumbo jumbo string or string array thingy, ending up with this (for the non-array translations).

someValue.replace("xxx", this.util.getI18n("Donkey") as string);

有没有办法为 TypeScript 解释输出string,即使它可能是 string[]在其他情况下?

Is there a way to explain for TypeScript that the output is string even if it might be string[] in other cases?

推荐答案

可以通过泛型类型属性来实现效果.考虑:

You can achieve the effect by generic type property. Consider:

function getI18n<A extends string[] | string>(id: A): A { 
    return id; // example implementation
}

const arr = getI18n(['a', 'b']) // arr is string[]
const str = getI18n('a') // str is string

<小时>

通用方法的缺点

由于该解决方案非常适用于 id 函数,问题始于任何实现,TS 抱怨类型,好像唯一的方法是不加任何修改地传递参数.考虑:


The downside of generic approach

As the solution works great for id function, the issue starts with any implementation, TS is complaining about types as if the only way is to pass arguments without any modifications. Consider:

function getI18n<A extends string[] | string>(id: A): A { 
    if (typeof id === 'string') {
        return id.concat('suffix') as A; 
    } else {
        return (id as string[]).map(x => x.concat('suffix')) as A;
    }
}

解决方案很好,但我们需要考虑一些事情:

The solution works nice, but we need to consider some things:

  • 需要在函数体中使用类型断言
  • 代码没有很好地显示什么输入类型映射到什么输出(重载显示)
  • 输出的类型推断将错误地推断输入的类型

最后一点问题可以在下面的例子中查看:

The last point issue can be viewed in the example below:

const str = getI18n('a') // str is type "a"

所以输出类型是a",但在示例中实现结果将是一个字符串asuffix",所以类型是错误的.

So output type is "a" but in example implementation result will be a string "asuffix", so the type is wrong.

我想在整个主题中添加一件事.我们需要拥有这种多态输入的事实通常是通过常见的 JS 方法继承的,这样的事情在历史上被认为是良好的做法.但在现实中,具有特定输入的功能会更好,它会产生更少的混乱和问题.

I want to add one thing to the whole topic. The fact that we have the demand to have such polymorphic input is generally inherited with common JS approach, were such things are considered as historically good practice. But in reality function which has specific one input will be better, it creates less confusion and questions.

创建具有单态类型的函数.

Create function with monomorphic type.

function getI18n(ids: string[]): string[] { 
    return ids.map(id => id + "suffix");
}

const arr = getI18n(['a', 'b'])
const str = getI18n(['a'])

就这么简单.该方法的好处:

Simple as that. Benefits of the approach:

  • 没有类型级别的条件
  • 没有价值层面的条件
  • 没有问题 - f 会为这样那样的输入返回什么

将字符串放入数组括号中确实没有成本.

There is really no cost in putting a string into array brackets.

这篇关于如何在不使用 as 的情况下确保 TypeScript 的 string|string[] 是 string?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆