2

我想将单个数组const fruits = ['banana', 'apple', 'orange']用作普通数组,并将type.

我应该能够做到这一点: const x: fruits // => only accepts 'banana', 'apple' or 'orange'

并且还能够做到这一点: @IsIn(fruits)


我试图将数组声明为<const>,例如:

const fruits = <const>['banana', 'apple', 'orange']
type Fruits = typeof fruits[number] // this evaluates to type: "banana" | "apple" | "orange"

但是@IsIn(fruits)会返回以下错误:

Argument of type 'readonly ["banana", "apple", "orange"]' is not assignable to parameter of type 'any[]'.
  The type 'readonly ["banana", "apple", "orange"]' is 'readonly' and cannot be assigned to the mutable type 'any[]'.ts(2345)

所以我想如果我创建了两个数组,一个普通数组和一个只读数组,它应该可以工作。所以我尝试了这个:

const fruits = ['banana', 'apple', 'orange']
const fruits_readonly: <const>[...fruits]
type Fruits = typeof fruits_readonly[number]

但现在Fruits评估为type: string而不是type: "banana" | "apple" | "orange".

4

1 回答 1

2

确实,const断言readonly会产生带有元素的对象和数组。如果您想获得const断言为您带来的字符串文字和元组类型的好处,同时也readonly取消结果,您可以编写一个辅助函数来做到这一点。我会这样称呼它mutable()

const mutable = <T>(t: T): { -readonly [K in keyof T]: T[K] } => t

const fruits = mutable(['banana', 'apple', 'orange'] as const);
// const fruits: ["banana", "apple", "orange"]

这将深入一层。如果您有嵌套的对象/数组类型,您可能想要创建一个DeepMutable类型和deepMutable()辅助函数:

type DeepMutable<T> =
    T extends object ? { -readonly [K in keyof T]: DeepMutable<T[K]> } : T

const deepMutable = <T>(t: T) => t as DeepMutable<T>;

对于上述情况,这同样适用,

const alsoFruits = deepMutable(['banana', 'apple', 'orange'] as const);
// const alsoFruits: ["banana", "apple", "orange"]

但是对于嵌套对象,区别变得很重要:

const readonlyDeepFruits = {
    yellow: ["banana", "lemon"],
    red: ["cherry", "apple"],
    orange: ["orange", "mango"],
    green: ["lime", "watermelon"]
} as const;
/* const readonlyDeepFruits: {
    readonly yellow: readonly ["banana", "lemon"];
    readonly red: readonly ["cherry", "apple"];
    readonly orange: readonly ["orange", "mango"];
    readonly green: readonly ["lime", "watermelon"];
} */

const partiallyMutableDeepFruits = mutable(readonlyDeepFruits);
/* const partiallyMutableDeepFruits: {
    yellow: readonly ["banana", "lemon"];
    red: readonly ["cherry", "apple"];
    orange: readonly ["orange", "mango"];
    green: readonly ["lime", "watermelon"];
} */

const fullyMutableDeepFruits = deepMutable(readonlyDeepFruits);
/* const fullyMutableDeepFruits: {
    yellow: ["banana", "lemon"];
    red: ["cherry", "apple"];
    orange: ["orange", "mango"];
    green: ["lime", "watermelon"];
} */

好的,希望有帮助。祝你好运!

链接到代码

于 2019-11-05T17:13:36.983 回答