[英]How do I declare a read-only array tuple in TypeScript?
We can declare a typed tuple in TypeScript, for example, with the type annotation [string, number]
. 我们可以在TypeScript中声明一个类型化的元组,例如,类型注释[string, number]
。 This means an array of 2 elements where the first element needs to be a string and the second a number. 这意味着一个包含2个元素的数组,其中第一个元素需要是一个字符串,第二个元素需要一个数字。
We can also declare read-only arrays with ReadonlyArray<string>
which means a read-only array of strings. 我们还可以使用ReadonlyArray<string>
声明只读数组,这意味着ReadonlyArray<string>
数组。
Now I want to have a read-only tuple like in the first example, but I want it to be read-only like in the second example. 现在我想在第一个例子中有一个只读元组,但我希望它像第二个例子中那样是只读的。 How would I declare that? 我该如何申报?
Since the type [string, number]
already is an Array
, you can simply use: 由于类型[string, number]
已经是一个Array
,你可以简单地使用:
Readonly<[string, number]>
Example: 例:
let tuple: Readonly<[string, number]> = ['text', 3, 4, 'another text'];
tuple[0] = 'new text'; //Error (Readonly)
let string1: string = tuple[0]; //OK!
let string2: string = tuple[1]; //Error (Type number)
let number1: number = tuple[0]; //Error (Type string)
let number2: number = tuple[1]; //OK!
let number3: number = tuple[2]; //Error (Type any)
The accepted answer leaves array mutation methods unaffected, which can cause unsoundness in the following way: 接受的答案会使阵列变异方法不受影响,这可能会导致以下方式造成不健全:
const tuple: Readonly<[number, string]> = [0, ''];
tuple.shift();
let a = tuple[0]; // a: number, but at runtime it will be a string
The code below fixes this issue, and includes Sergey Shandar's destructuring fix. 下面的代码解决了这个问题,包括Sergey Shandar的解构修复。 You'll need to use --noImplicitAny
for it to work properly. 您需要使用--noImplicitAny
才能正常工作。
type ArrayItems<T extends ReadonlyArray<any>> = T extends ReadonlyArray<infer TItems> ? TItems : never;
type ExcludeProperties<TObj, TKeys extends string | number | Symbol> = Pick<TObj, Exclude<keyof TObj, TKeys>>;
type ArrayMutationKeys = Exclude<keyof any[], keyof ReadonlyArray<any>> | number;
type ReadonlyTuple<T extends any[]> = Readonly<ExcludeProperties<T, ArrayMutationKeys>> & {
readonly [Symbol.iterator]: () => IterableIterator<ArrayItems<T>>;
};
const tuple: ReadonlyTuple<[number, string]> = [0, ''];
let a = tuple[0]; // a: number
let b = tuple[1]; // b: string
let c = tuple[2]; // Error when using --noImplicitAny
tuple[0] = 1; // Error
let [d, e] = tuple; // d: number, e: string
let [f, g, h] = tuple; // Error
It looks like there will be a clean solution for this requirement coming with TypeScript 3.4 version: 对于TypeScript 3.4版本的这一要求,看起来会有一个干净的解决方案:
With so-called const contexts , the compiler can be told to treat an array or an object as immutable, meaning that their properties are read-only. 使用所谓的const上下文 ,可以告诉编译器将数组或对象视为不可变的,这意味着它们的属性是只读的。 This also allows the creation of literal tuple types with narrower type inference (ie your ["a", "b"]
can for the first time be of type ["a", "b"]
, not string[]
without specifiying the whole thing as a contextual type) 这也允许创建具有较窄类型推断的文字元组类型(即,您的["a", "b"]
第一次可以是["a", "b"]
,而不是string[]
而不指定整个事物作为上下文类型)
The syntax will look like this: 语法如下所示:
let foo = ["text", 1] as const
or 要么
let foo = <const> ["text", 1]
Here is the extended information of the corresponding PR. 这是相应PR 的扩展信息 。 As of now, the feature should be available in typescript@next
. 截至目前,该功能应该在typescript@next
。
Readonly<[string, T]>
doesn't allow destruction. Readonly<[string, T]>
不允许销毁。 For example 例如
const tuple: Readonly<[string, number]> = ["text", 4]
const [n, v] = tuple // error TS2488: Type 'Readonly<[string, number]>' must have a '[Symbol.iterator]()' method that returns an iterator.
So, it's better to use a custom interface 因此,最好使用自定义界面
export interface Entry<T> {
readonly [0]: string
readonly [1]: T
readonly [Symbol.iterator]: () => IterableIterator<string|T>
}
For example 例如
const tuple: Entry<number> = ["text", 4]
const [name, value] = tuple // ok
const nameCheck: string = name
const valueCheck: number = value
From Typescript version 3.4 you can just prefix tuple type with readonly
keyword ( source ). 从Typescript版本3.4开始,您只需使用readonly
关键字( source )为元组类型添加前缀。
TypeScript 3.4 also introduces new support for
readonly
tuples. TypeScript 3.4还为readonly
元组引入了新的支持。 We can prefix any tuple type with thereadonly
keyword to make it areadonly
tuple, much like we now can with array shorthand syntax. 我们可以使用readonly
关键字为任何元组类型添加前缀,使其成为一个readonly
元组,就像我们现在可以使用数组简写语法一样。 As you might expect, unlike ordinary tuples whose slots could be written to,readonly
tuples only permit reading from those positions. 正如您所料,与可以写入插槽的普通元组不同,readonly
元组只允许从这些位置读取。function foo(pair: readonly [string, string]) { console.log(pair[0]); // okay pair[1] = "hello!"; // error }
As of v3.2.2, there's no perfect way of making a readonly tuple type without converting it to an object that looks like an array, but is not. 从v3.2.2开始,没有完美的方法来制作只读元组类型而不将其转换为看起来像数组的对象,但事实并非如此。
The lead architect of TypeScript has said this on the topic of combining Readonly<T>
with tuple types. 打字本架构师所说这对相结合的话题Readonly<T>
用的元组类型。
Here is the best solution I've come up with: 这是我提出的最佳解决方案:
type ReadonlyTuple<T extends any[]> = {
readonly [P in Exclude<keyof T, keyof []>]: T[P]
} & Iterable<T[number]>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.