TypeScript技术问询:如何将已定义的字符串数组转换为只读字面量数组
首先得说清楚为什么你尝试的 const readonlyArr = arr as const 不生效:当你写 const arr = ["a", "b"] 时,TypeScript 会把 arr 的类型推断为 string[]——虽然 arr 是用 const 声明的,但数组本身是可变的(你可以修改它的元素,比如 arr[0] = "c"),所以 TypeScript 会自动把元素类型拓宽为 string,而不是保留 "a"、"b" 这些具体的字面量类型。这时候 as const 没法凭空恢复已经丢失的字面量信息,自然就达不到你想要的效果。
那怎么解决这个问题呢?分几种情况来看:
情况1:你还能修改arr的定义
如果你还没把 arr 的定义写死,可以在定义 arr 的时候就用 as const 来锁定字面量类型,这样后续直接复用这个类型就好:
// 定义时就用as const,arr的类型会被推断为readonly ["a", "b"] const arr = ["a", "b"] as const; const readonlyArr = arr; // 直接赋值,类型就是readonly ["a", "b"]
要是你需要 arr 本身是可变的(比如后续要修改元素),可以拆分两步:
// 先定义只读字面量数组,保留具体类型 const arrLiteral = ["a", "b"] as const; // 再转成可变的string[]用于后续修改 const arr: string[] = [...arrLiteral]; // 用arrLiteral作为只读字面量数组使用 const readonlyArr = arrLiteral;
情况2:arr已经是定义好的string[]
如果 arr 已经是一个 string[] 类型的变量,且你明确知道它的元素是哪些具体的字面量,可以手动断言成只读字面量数组:
const arr = ["a", "b"]; // 手动指定字面量类型,断言为只读数组 const readonlyArr = arr as readonly ["a", "b"];
这种方法需要你手动写出所有元素的字面量,虽然不够灵活,但适合你清楚 arr 内容的场景。
额外说明
这里要注意:一旦 TypeScript 把数组推断为 string[],它就丢失了具体的字面量信息,没办法自动从 string[] 逆向推导出 readonly ["a", "b"] 这种具体类型——毕竟 string[] 可以包含任意字符串元素,TypeScript 不知道你指的是哪几个具体值。所以最稳妥的方式还是在定义数组时就用 as const 保留字面量类型,避免类型拓宽。
内容的提问来源于stack exchange,提问作者Lenka Hubáčková

