简体   繁体   English

如何在TypeScript中声明只读数组元组?

[英]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

Solution in Typescript 3.4: Const Contexts Typescript 3.4中的解决方案:Const上下文

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 the readonly keyword to make it a readonly 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.

相关问题 如何在Typescript中强制只读数组具有带字符串文字的元组类型? - How to force read-only arrays to have a tuple type with string literals in Typescript? 如何在Typescript中声明给定大小的多维数组 - How do I declare a Multidimensional Array of a given size in Typescript 如何在 TypeScript 的 for..of 循环中声明和解构元组数组? - How to Declare and Destructure a Tuple Array in a for..of Loop in TypeScript? 在Typescript中,我如何声明一个返回字符串类型数组的函数? - In Typescript how do I declare a function that return string type array? 如何在打字稿中声明公共枚举? - How do I declare a public enum in typescript? 如何在Typescript中声明NodeJs模块? - How do I declare a NodeJs module in Typescript? 如何将 TypeScript 变量声明为 volatile? - How do I declare a TypeScript variable as volatile? 如何声明两个数字元组的返回类型? - How do I declare a return type of a tuple of two numbers? 在TypeScript中,如何声明接受字符串并返回字符串的函数数组? - In TypeScript how do I declare an array of functions that accept a string and return a string? 如何在 TypeScript 中同时使用“Pick”和“&amp;”关键字声明数组 object 的类型 - How do I declare a type for array object using 'Pick' and '&' keyword at the same time in TypeScript
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM