这个问题对我来说有点难以表达,这可能是我在研究中没有发现任何东西的原因.

我试图得到一个最终只有数组的类型.我总是希望最终得到"一级"数组(如果给定了数组的数组,我不关心输出.在我的情况下不会发生这种情况).因此,想要的结果如下:

type T1 = ForceArray<string> // wanted: string[]

type T2 = ForceArray<string[]> // wanted: string[]

我可以通过以下代码来实现这一点:

type ForceArray<T> = NonNullable<T> extends Array<any> ? T : Array<T>

这里使用NonNullable是因为在实际用例中,ForceArray<T>用于接口属性,这是可选的.除了联合类型之外,这种方法效果很好.

type T3 = ForceArray<string | string[]> // shows (string | string[])[] but I want string[]

此外,其他联合类型也应转换为不起作用的数组:

type T4 = ForceArray<number | string[]> // wanted: number[] | string[]

type T5 = ForceArray<number[] | string> // wanted: number[] | string[]

在typescript文档中,他们提到了Distributive conditional types个.但就我对文档的理解而言,我的代码应该可以正常工作.所以很明显我没有正确理解文档.

有没有办法达到预期的行为?


Additional information:

产生输出的实际代码非常简单,这就是为什么我认为应该有一个解决方案:

const forceArray = (value) => Array.isArray(value) ? value : [value];

此函数用于这样的上下文,其中obj可以实现任何接口(具有可选属性):

const convertObjectValuesToArray = (obj) => {
    const newObj = {};
    for (const key of obj) {
        newObj[key] = forceArray(obj[key]);
    }
    return newObj;
}

推荐答案

NonNullable似乎是这里的问题,因为它禁用了类似于括号[]的泛型类型的分布性.我们可以删除它,用它来替换返回的类型.

type ToArray<Type> = Type extends Array<any> ? NonNullable<Type> : NonNullable<Type>[]

type A = ToArray<string>              // string[]
type B = ToArray<string[]>            // string[]
type C = ToArray<string | number[]>   // string[] | number[]
type D = ToArray<string | null>       // string[] | never[]

这里唯一的问题是返回类型为string[] | never[]D.但我们可以用Exclude来代替never

type ToArray<Type> = Exclude<Type extends Array<any> ? NonNullable<Type> : NonNullable<Type>[], never[] | never>

type A = ToArray<string>              // string[]
type B = ToArray<string[]>            // string[]
type C = ToArray<string | number[]>   // string[] | number[]
type D = ToArray<string | null>       // string[]

Typescript相关问答推荐

Angular 17 -如何在for循环内创建一些加载?

如何防止TypeScript允许重新分配NTFS?

对深度对象键/路径进行适当的智能感知和类型判断,作为函数参数,而不会触发递归类型限制器

rxjs forkJoin在错误后不会停止后续请求

编剧错误:正在等待Expect(Locator).toBeVisible()

PrimeNG日历需要找到覆盖默认Enter键行为的方法

如何在Angular 12中创建DisplayBlock组件?

为什么我的动画状态在组件实例之间共享?

在类型脚本中将泛型字符串数组转换为字符串字母并集

将接口映射到交叉口类型

map 未显示控制台未显示任何错误@reaction-google-map/api

具有匹配功能的TS通用事件处理程序

我可以将一个类型数组映射到TypeScrip中的另一个类型数组吗?

可以将JS文件放在tsconfig';s includes/files属性?或者,我如何让tsc判断TS项目中的JS文件?

如何避免TS2322;类型any不可分配给类型never;使用索引访问时

在ts中获取级联子K类型?

如何让Record中的每个值都有独立的类型?

使用 fp-ts 时如何使用 TypeScript 序列化任务执行?

根据索引将元组拆分为两个块

使用react+ts通过props传递数据