我们可以在TypeScript中声明一个类型化元组,例如,使用类型注解[string, number],这意味着一个包含2个元素的数组,其中第一个元素需要是字符串,第二个元素需要是数字。我们也可以用ReadonlyArray<string>声明只读数组,这意味着字符串的只读数组。现在我想有一个只读元组,就像第一个例子一样,但是我想让它像第二个例子一样是只读的,我该怎么声明呢?
[string, number]
ReadonlyArray<string>
hsgswve41#
由于类型[string, number]已经是Array,因此可以简单地使用:Readonly<[string, number]>示例:
Array
Readonly<[string, number]>
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)
apeeds0o2#
使用constAssert,编译器可以被告知将数组或对象视为不可变的,这意味着它们的属性是只读的。这也允许创建具有更窄类型推断的文本元组类型(即,您的["a", "b"]可以是["a", "b"]类型,而不是string[]类型,而无需将整个对象指定为上下文类型)语法:
["a", "b"]
string[]
const foo = ["text", 1] as const // or const foo = <const> ["text", 1] // typeof foo: readonly ["text", 1]
它也可以用于对象文本:
const myObj = { foo: 1, bar: ["a", "b"], baz: true, } as const // typeof myObj: { readonly foo: 1, readonly bar: readonly ["a", "b"], readonly baz: true }
对应PR的Here is the extended information。
tkclm6bt3#
从Typescript 3.4版开始,您可以只在元组类型前面加上readonly关键字(源代码)。TypeScript 3.4还引入了对readonly元组的新支持。我们可以在任何元组类型的前面加上readonly关键字,使其成为readonly元组,就像我们现在使用数组速记语法所做的那样。正如您所期望的,与插槽可以写入的普通元组不同,readonly元组只允许从这些位置阅读。
readonly
function foo(pair: readonly [string, string]) { console.log(pair[0]); // okay pair[1] = "hello!"; // error }
jckbn6z74#
接受的答案不影响数组变异方法,这可能会以下列方式导致不合理:
const tuple: Readonly<[number, string]> = [0, '']; tuple.shift(); let a = tuple[0]; // a: number, but at runtime it will be a string
下面的代码修复了这个问题,并且包含了Sergey Shandar的重构修复。你需要使用--noImplicitAny来使它正常工作。
--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
cpjpxq1n5#
Readonly<[string, T]>不允许销毁。例如
Readonly<[string, T]>
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.
因此,最好使用自定义接口
export interface Entry<T> { readonly [0]: string readonly [1]: T readonly [Symbol.iterator]: () => IterableIterator<string|T> }
例如
const tuple: Entry<number> = ["text", 4] const [name, value] = tuple // ok const nameCheck: string = name const valueCheck: number = value
hyrbngr76#
从v3.2.2开始,没有一种完美的方法可以创建一个只读元组类型,而不将其转换为一个 * 看起来 * 像数组的对象,但实际上不是。TypeScript的首席架构师在讨论将Readonly<T>与元组类型结合时说过这一点。下面是我想出的最佳解决方案:
Readonly<T>
type ReadonlyTuple<T extends any[]> = { readonly [P in Exclude<keyof T, keyof []>]: T[P] } & Iterable<T[number]>
8wtpewkr7#
您可以在创建数组时调用Object.freeze,使其成为只读。
Object.freeze
const arr = Object.freeze(["text", 2, 3]);
这会自动将类型转换为TypeScript中的readonly (string | number)[],并且在运行时也是只读的。
readonly (string | number)[]
7条答案
按热度按时间hsgswve41#
由于类型
[string, number]
已经是Array
,因此可以简单地使用:Readonly<[string, number]>
示例:
apeeds0o2#
TypeScript 3.4+的解决方案:常量Assert
使用constAssert,编译器可以被告知将数组或对象视为不可变的,这意味着它们的属性是只读的。这也允许创建具有更窄类型推断的文本元组类型(即,您的
["a", "b"]
可以是["a", "b"]
类型,而不是string[]
类型,而无需将整个对象指定为上下文类型)语法:
它也可以用于对象文本:
对应PR的Here is the extended information。
tkclm6bt3#
从Typescript 3.4版开始,您可以只在元组类型前面加上
readonly
关键字(源代码)。TypeScript 3.4还引入了对
readonly
元组的新支持。我们可以在任何元组类型的前面加上readonly
关键字,使其成为readonly
元组,就像我们现在使用数组速记语法所做的那样。正如您所期望的,与插槽可以写入的普通元组不同,readonly
元组只允许从这些位置阅读。jckbn6z74#
接受的答案不影响数组变异方法,这可能会以下列方式导致不合理:
下面的代码修复了这个问题,并且包含了Sergey Shandar的重构修复。你需要使用
--noImplicitAny
来使它正常工作。cpjpxq1n5#
Readonly<[string, T]>
不允许销毁。例如因此,最好使用自定义接口
例如
hyrbngr76#
从v3.2.2开始,没有一种完美的方法可以创建一个只读元组类型,而不将其转换为一个 * 看起来 * 像数组的对象,但实际上不是。
TypeScript的首席架构师在讨论将
Readonly<T>
与元组类型结合时说过这一点。下面是我想出的最佳解决方案:
8wtpewkr7#
您可以在创建数组时调用
Object.freeze
,使其成为只读。这会自动将类型转换为TypeScript中的
readonly (string | number)[]
,并且在运行时也是只读的。