如何确保TypeScript字符串| string[]是字符串而不使用as?

如何确保TypeScript字符串| string[]是字符串而不使用as?,typescript,types,Typescript,Types,编辑 由于时间的推移,它已经失去了它的有效性,因为它似乎从评论和回答这一个。尽管最初的外观,这不是一个愚弄这一个 我有一个翻译器功能,通过以下签名工作 getI18n(id: string) : string { ... } getI18n(id: string | string[]) : string | string[] { ... } 我注意到输入以下内容有点乏味 const titles = [ this.util.getI18n("Donkey"), this.util.g

编辑
由于时间的推移,它已经失去了它的有效性,因为它似乎从评论和回答这一个。尽管最初的外观,这不是一个愚弄这一个

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

getI18n(id: string) : string { ... }
getI18n(id: string | string[]) : string | string[] { ... }
我注意到输入以下内容有点乏味

const titles = [
  this.util.getI18n("Donkey"),
  this.util.getI18n("Monkey"),
  ...
  this.util.getI18n("Wonkey")
];
我喜欢用这样的东西

const titles = this.util.getI18n(["Donkey", "Monkey", ..., "Wonkey"]);
所以我引入了一个函数,它接受字符串和带有以下签名的字符串[]

getI18n(id: string) : string { ... }
getI18n(id: string | string[]) : string | string[] { ... }
这让我觉得很天才,直到我注意到我必须为愚蠢的打字脚本解释结果是字符串,而不是一些杂乱无章的字符串或字符串数组之类的东西,最后是这个(对于非数组翻译)


有没有一种方法可以解释TypeScript的输出是string,即使它在其他情况下可能是string[]?

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

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
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;
    }
}
所以输出类型是“a”,但在示例中,实现结果将是字符串“asuffix”,所以类型是错误的

不要这样做,函数应该有一个输入类型 我想在整个主题中增加一点。事实上,我们需要这种多态性输入,这通常是通过普通的JS方法继承的,如果这些东西被认为是历史上的良好实践的话。但在现实中,有特定一个输入的函数会更好,它会减少混乱和问题

创建单态类型的函数

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

const arr = getI18n(['a', 'b'])
const str = getI18n(['a'])
就这么简单。这种方法的好处:

  • 类型级别上没有条件
  • 没有关于价值水平的条件
  • 没有问题-f将为这样或那样的输入返回什么

将字符串放入数组括号中实际上没有成本。

除了泛型之外,还可以使用函数重载

function getI18n(id: string[]): string[];
function getI18n(id: string): string;
function getI18n(id: string | string[]): string | string[] {
    if (typeof id === 'string') {
        return id + '_title';
    }
    return id.slice();
}

const title = getI18n('test'); // const title: string
const titles = getI18n(['a', 'b', 'c']); // const titles: string[]

此功能上的官方文档链接:

使用两种不同的功能(getI18n和getI18ns),因为它们的功能不同。或使用重载函数:。TypeScript一点也不愚蠢:你的函数声明说你的函数有时返回一个字符串,有时返回一个字符串[]。重载是一个好主意,但它不起作用,因为“所有重载必须具有相同的返回类型”-@JBNizet I(部分)不同意你基于以下内容的观点。TS的一个有效特性是允许不确定的返回类型。基于JS范式(TS transpiles to),勇敢者应该尝试假设最佳情况。所以我认为这个方法应该看到哦,它实际上可能是一个字符串,而不是哦,不,它可能不是一个字符串。这感觉有点太离谱了。另外,您能给我指出一个允许无限返回类型的重载资源吗?我所发现的只是接收未定义的内容,而不是返回它们。在我的例子中,这一部分非常有效。@Suma,这个链接是针对Java的。不是JavaScript,不是吗?你是不是把火腿和仓鼠搞混了?还是我的脑子太慢了,没有领会你的意思?@KonradViltersten不,这是打字稿。这篇文章叫做“类型脚本函数或方法重载”。只有该网站的名称中包含Java。您确定吗?我读过的所有文章都声明所有重载必须具有相同的返回类型。。。但是在TypeScript v3.7.2中进行测试似乎真的很有效。也许我读过的文章都是旧的,同时又取消了限制?如果这一点能够得到证实并添加到答案中,那就太好了。有一篇文章特别提到了这一技术:不过,如果发现这一点发生了变化,或者其他文章(如)是否有错,这将是很有趣的。最近的规范肯定允许这一点:如果候选列表包含一个或多个签名,且每个参数表达式的类型是每个相应参数类型的子类型,则这些签名中第一个签名的返回类型将成为函数调用的返回类型。“@MaciejSikora我不确定我是否同意你因断言要求而拒绝使用泛型。我们只是在方法内部断言,而输出将自动正确理解,不是吗?虽然我很欣赏通过直接重载的解决方案,但我感觉不太信任方法数量的增加。特别是,我认为可以考虑其他类型,并产生各自的输出类型。如果这些可以用相同的语法处理,并且我们只需要对类型的不确定性进行TS-STFU,那么我们就要失败了。你怎么看?只是想说得更清楚一些。您的意思是,它应该类似于if(typeof(A==“string”))returndostring(id),而不是returnid;返回方向(id);,正确的?如果是这样的话,应该对答案进行修改,因为这可能会让noobs感到困惑。如果你愿意,我可以把它放进去。但我更愿意得到你们的确认,我把你们的观点说对了,所以我不会篡改好的答案,让它变得更糟。你们说你们在类型推断方面有问题。函数体的操作方式不会影响类型,typeof检查是运行时检查。但如果我们问如何实现这一点,那么是的,您需要检查输入是否是字符串,typeof是否是个好主意。但是从TS的角度来看,不可能理解您的实现是否正确,您甚至可以像字符串返回数组那样反向执行,TS不会抱怨您完全正确,这表明我明白您的意思。我的请求是基于一位初级同事,他不理解这个把戏,并质疑我的解释。他们建议只要返回发送的内容就足够了,就好像您的示例实现实际上是功能性的(当然在语法上是有效的),而我认为这只是一个琐碎的问题(与实际问题无关)。当然,如果您觉得不合适,我不会胡扯您的贡献。只是在讨论中引入不同的观点。回答的重点主要是帮助(最好是正确的)一