简体   繁体   English

打字稿:具有相同项目类型的字符串联合和完整数组的 DRY 定义

[英]Typescript: DRY definition of string union and full array with the same item type

As shown elsewhere (eg TypeScript String Union to String Array ) it is easy to define union type from tuple:如别处所示(例如TypeScript String Union to String Array )很容易从元组定义联合类型:

const arr = ["foo", "bar"] as const
const Item = typeof arr[number]

Unfortunately I cannot use arr where Item[] is required - the type of arr is readonly ["foo", "bar"] , and even direct type cast results in typescript error TS2352.不幸的是,我不能在需要Item[]地方使用arr - arr的类型是readonly ["foo", "bar"] ,甚至直接类型转换也会导致打字稿错误 TS2352。

Typescripts suggests to cast to unknown first - it works but it looks confusing and kind of defeats the whole purpose of type-safe array constant: Typescripts 建议先转换为unknown - 它有效,但它看起来令人困惑并且有点违背了类型安全数组常量的全部目的:

const _arr: Item[] = (arr as unknown) as Item[]

Is there any better way to have both the full list of options as Item[] and Item union type without repeating the actual options, other than above double cast?除了上面的双重转换之外,有没有更好的方法可以将完整的选项列表作为Item[]Item union type 而不重复实际选项?

What you want to do is type-unsafe .您想要做的是type-unsafe Given给定的

const arr = ["foo", "bar"] as const

If you could type the same arr as Item[] when using it somewhere, and then (for example) pass it to a function which accepts Item[] as a parameter, that function could then do:如果您可以在某处使用它时键入与Item[]相同的arr ,然后(例如)将其传递给接受Item[]作为参数的函数,则该函数可以执行以下操作:

arrayParameter.push('foo');

which would be perfectly fine because the parameter would still remain an Item[] .这完全没问题,因为参数仍然是Item[] But the original type is now incorrect, because the mutated arr is no longer ["foo", "bar"] as const - rather, it has 3 items.但是原始类型现在不正确,因为变异的arr不再是["foo", "bar"] as const - 相反,它有 3 个项目。

Slice (or otherwise somehow shallow copy) the array first if you want to use it as a generic Item[] .如果您想将数组用作通用Item[]请先切片(或以其他方式以某种方式浅拷贝)数组。 There's no other way to do this which would be type-safe.没有其他方法可以做到这一点,这是类型安全的。

const arr = ['foo', 'bar'] as const;
type Item = typeof arr[number];
const arrItems: Item[] = arr.slice();

if your function takes readonly string[] this as input, then you can pass existing arr, I know you might not have a control or change the function signature, but just throwing this out in case it helps如果您的函数将readonly string[] this 作为输入,那么您可以传递现有的 arr,我知道您可能没有控制权或更改函数签名,但只是将其扔掉以防万一

const tuple = ['foo', 'bar'] as const


function println(arr: readonly string[]) {
  console.log(arr)
}

println(tuple)
println(['a', 'b', 'c'])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM