0

使用const assertion,可以很好地将对象/数组文字的类型缩小到它的元素。

例如

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

错误是:

type'readonly [readonly [5, "hello"], readonly [5, "bye"]]'的参数不能分配给 type 的参数'[5, string][]'。该类型'readonly [readonly [5, "hello"], readonly [5, "bye"]]''readonly'并且不能分配给可变类型'[5, string][]'。(2345)

问题

如何在不获取不需要的readonly属性的情况下缩小类型?(最好在对象/数组创建时。)

4

2 回答 2

1

Typescriptas运算符对我来说看起来有点 hacky。我试图尽可能地避免它。请尝试下一个示例:

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

操场

于 2020-11-21T16:14:43.693 回答
0

为了摆脱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!

TS 游乐场链接。

这样,对象只被操作/转换一次,它可以在任何地方用作普通的、类型缩小的、非只读变量!

于 2020-11-21T14:05:22.433 回答