我们可以在TypeScript中声明一个类型化的元组,例如,使用类型注释[string, number].这意味着一个包含2个元素的数组,其中第一个元素需要是一个字符串,第二个元素需要一个数字.
我们还可以声明只读数组,ReadonlyArray<string>这意味着只读数组的字符串.
现在我想在第一个例子中有一个只读元组,但我希望它像第二个例子中那样是只读的.我该如何申报?
Arg*_*g0n 11
由于该类型[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)
Run Code Online (Sandbox Code Playgroud)
接受的答案会使阵列变异方法不受影响,这可能会导致以下方式造成不健全:
const tuple: Readonly<[number, string]> = [0, ''];
tuple.shift();
let a = tuple[0]; // a: number, but at runtime it will be a string
Run Code Online (Sandbox Code Playgroud)
下面的代码解决了这个问题,包括Sergey Shandar的解构修复.您需要使用--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
Run Code Online (Sandbox Code Playgroud)
从 Typescript 3.4 版开始,您可以在元组类型前加上readonly关键字(source)。
TypeScript 3.4 还引入了对
readonly元组的新支持。我们可以使用readonly关键字为任何元组类型添加前缀以使其成为readonly元组,就像我们现在可以使用数组速记语法一样。正如您所料,与可以写入插槽的普通元组不同,readonly元组只允许从这些位置读取。Run Code Online (Sandbox Code Playgroud)function foo(pair: readonly [string, string]) { console.log(pair[0]); // okay pair[1] = "hello!"; // error }
看来TypeScript 3.4版本会提供针对此要求的干净解决方案:
使用所谓的const上下文,可以告诉编译器将数组或对象视为不可变的,这意味着它们的属性是只读的。这还允许创建具有更窄类型推断的文字元组类型(即,您 ["a", "b"]可以第一次使用type ["a", "b"],而不是string[]将整个事物指定为上下文类型)
语法如下所示:
let foo = ["text", 1] as const
Run Code Online (Sandbox Code Playgroud)
要么
let foo = <const> ["text", 1]
Run Code Online (Sandbox Code Playgroud)
这是相应PR 的扩展信息。到目前为止,该功能应该在中可用typescript@next。