提问人:Aidin 提问时间:11/21/2020 更新时间:9/18/2021 访问量:871
打字稿:[编译时间] 可写(-可读)数组/对象,具有“as const”类型缩小
Typescript: [Compile Time] Writable (- readable) array/object with "as const" type narrowing
问:
使用 const 断言,可以很好地将对象/数组文本的类型缩小到其元素。
例如:
const arr = [
[5, "hello"],
[5, "bye"],
] as const;
type T = typeof arr; // type T = readonly [readonly [5, "hello"], readonly [5, "bye"]]
(如果没有 ,将是 ,这是非常宽泛的,有时是不需要的。as const
T
type T = (string | number)[][]
现在,问题是,由于数组也变得如此,而我只是让它有一个缩小的类型。因此,它不能传递给以下函数。as const
readonly
function fiveLover(pairs: [5, string][]): void {
pairs.forEach((p) => console.log(p[1]));
}
fiveLover(arr); // Error
错误是:
类型的参数不能分配给类型的参数。 该类型是且不能分配给可变类型。(2345)
'readonly [readonly [5, "hello"], readonly [5, "bye"]]'
'[5, string][]'
'readonly [readonly [5, "hello"], readonly [5, "bye"]]'
'readonly'
'[5, string][]'
问题
如何在不获取不需要的属性的情况下缩小类型范围?(最好在对象/数组创建时。readonly
答:
为了摆脱属性并使对象或数组可变,我们需要以下实用程序函数:readonly
type DeepWritable<T> = { -readonly [P in keyof T]: DeepWritable<T[P]> };
(来源: https://stackoverflow.com/a/43001581)
现在我们可以做以下两件事之一:
解决方案1)使其在消耗时可变
那是:
fiveLover(arr as DeepWritable<typeof arr>);
这很棒,并且保持对象完好无损。但是,如果我们在多个地方使用数组进行类似的可变用法,我们需要每次都这样做。arr
解决方案 2) 使其在创建时可变
这是我在实际项目中所需要的,因为我在很多地方都使用了这个对象,而且它被只读会导致麻烦。arr
解决方案是定义一个实用函数,该函数在运行时只是一个标识函数,但在编译时,如下所示:DeepWritable
function writableIdentity<T>(x: T): DeepWritable<T> {
return x as DeepWritable<T>;
}
const arr2 = writableIdentity([
[5, "hello"],
[5, "bye"],
] as const);
fiveLover(arr2); // Works fine!
这样,对象只需操作/转换一次,并且可以在任何地方用作普通的、类型缩小的、非只读的变量!
打字稿运算符对我来说看起来有点笨拙。我试图尽可能地避免它。
请尝试下一个示例:as
const arr = [
[5, "hello"],
[5, "bye"],
] as const;
function fiveLover<T extends ReadonlyArray<readonly [5, string]>>(pairs: T): void {
pairs.forEach((p) => console.log(p[1]));
}
fiveLover(arr); // No Error
顺便说一句,我一直在尝试对不可变的值进行操作。如果你没有改变你的值,就没有理由删除标志readonly
更新
可以在没有的情况下进行推断,但您需要提供文字对象而不是引用。别无他法const assertion
function fiveLover<
Fst extends number,
Scd extends string,
Tuple extends [Fst, Scd],
Tuples extends Tuple[]
>(pairs: [...Tuples]): void {
pairs.forEach((p) => console.log(p[1]));
}
fiveLover([
[5, "hello"],
[5, "bye"],
]); // ok
评论
readonly<readonly<X>>
评论