我可以声明一种数组文字吗?
can I declare a type of an array literal?
在我的打字稿代码中,我有这个片段:
pairs.forEach(([n, s]) => {
console.log(n * 3, s.toUpperCase());
});
我想内联“pairs”变量。我知道我可以这样做:
([[3, "three"], [5, "five"]] as [number, string][]).forEach(([n, s]) => {
console.log(n * 3, s.toUpperCase());
});
但我不喜欢它,因为现在我的代码变得更糟了。在内联之前,编译器正在验证数组的每个元素都是一对数字和字符串 - 因此,例如,此代码无法编译:
const pairs: [number, string][] = [[3, "three"], [5, "five"], ["seven", 7]];
pairs.forEach(([n, s]) => {
console.log(n * 3, s.toUpperCase());
});
但是内联后,我的数组没有声明类型。相反,我使用类型断言,它告诉编译器忽略它认为的类型是什么,并相信我的话。所以现在编译器不会验证数组的每个元素都是一对数字和字符串。因此,例如,这段代码可以编译,但只会在运行时失败:
([[3, "three"], [5, "five"], ["seven", 7]] as [number, string][]).forEach(([n, s]) => {
console.log(n * 3, s.toUpperCase());
});
我能否以某种方式同时拥有这两个东西 - 都内联这个数组并告诉编译器它的类型是什么?我能以某种方式声明数组文字的类型吗?
我认为你不能真正自动完成。
在 let pairs = [[3, "three"], [5, "five"]]
中,pairs
的类型是 auto-detected 作为 (string | number)[][]
而不是 ([number,string][] )
这就是为什么在内联之后,它的行为不像你希望的那样,它只会使用它推断的 (string | number)[][]
。
似乎 auto-detect 一有机会就尝试检测 variable-length 数组而不是元组。
因此,let x = [3,4]
被检测为 number[]
而不是 [number,number]
和
let pair = [3,'three']
被检测为 (string|number)[]
而不是 [number,string]
您要找的魔法词是as const
:
([[1, 'foo'], [2, 'bar'], [3, 'baz']] as const)
.forEach(([n, s]) => console.log(n * 3, s.toLocaleUpperCase()));
请注意,as const
比您在此处寻找的更进一步:此数组的类型是
readonly [readonly [1, "foo"], readonly [2, "bar"], readonly [3, "baz"]]
并且 n
的类型是 1 | 2 | 3
而不是 number
并且 s
的类型是 "foo" | "bar" | "baz"
而不是 string
。 readonly
标记可能特别烦人,因为 readonly T[]
不能分配给 T[]
.
我经常使用as const
,因为它真的很强大,但我也经常在创建这样的元组时使用实用函数,但是不要想要将事物变成 readonly
个特定文字数组:
function tuple<T extends unknown[]>(...args: T): T { return args; }
(请注意,作为一个实际函数,这确实会引入运行时开销——as const
不会。但是它非常小。)
有了这个,我们就可以使用
tuple(tuple(1, 'foo'), tuple(2, 'bar'), tuple(3, 'baz'))
.forEach(([n, s]) => console.log(n * 3, s.toLocaleUpperCase()));
现在我们的数组是 [[number, string], [number, string], [number, string]]
,n
就是 number
,s
就是 string
。
在我的打字稿代码中,我有这个片段:
pairs.forEach(([n, s]) => {
console.log(n * 3, s.toUpperCase());
});
我想内联“pairs”变量。我知道我可以这样做:
([[3, "three"], [5, "five"]] as [number, string][]).forEach(([n, s]) => {
console.log(n * 3, s.toUpperCase());
});
但我不喜欢它,因为现在我的代码变得更糟了。在内联之前,编译器正在验证数组的每个元素都是一对数字和字符串 - 因此,例如,此代码无法编译:
const pairs: [number, string][] = [[3, "three"], [5, "five"], ["seven", 7]];
pairs.forEach(([n, s]) => {
console.log(n * 3, s.toUpperCase());
});
但是内联后,我的数组没有声明类型。相反,我使用类型断言,它告诉编译器忽略它认为的类型是什么,并相信我的话。所以现在编译器不会验证数组的每个元素都是一对数字和字符串。因此,例如,这段代码可以编译,但只会在运行时失败:
([[3, "three"], [5, "five"], ["seven", 7]] as [number, string][]).forEach(([n, s]) => {
console.log(n * 3, s.toUpperCase());
});
我能否以某种方式同时拥有这两个东西 - 都内联这个数组并告诉编译器它的类型是什么?我能以某种方式声明数组文字的类型吗?
我认为你不能真正自动完成。
在 let pairs = [[3, "three"], [5, "five"]]
中,pairs
的类型是 auto-detected 作为 (string | number)[][]
而不是 ([number,string][] )
这就是为什么在内联之后,它的行为不像你希望的那样,它只会使用它推断的 (string | number)[][]
。
似乎 auto-detect 一有机会就尝试检测 variable-length 数组而不是元组。
因此,let x = [3,4]
被检测为 number[]
而不是 [number,number]
和
let pair = [3,'three']
被检测为 (string|number)[]
而不是 [number,string]
您要找的魔法词是as const
:
([[1, 'foo'], [2, 'bar'], [3, 'baz']] as const)
.forEach(([n, s]) => console.log(n * 3, s.toLocaleUpperCase()));
请注意,as const
比您在此处寻找的更进一步:此数组的类型是
readonly [readonly [1, "foo"], readonly [2, "bar"], readonly [3, "baz"]]
并且 n
的类型是 1 | 2 | 3
而不是 number
并且 s
的类型是 "foo" | "bar" | "baz"
而不是 string
。 readonly
标记可能特别烦人,因为 readonly T[]
不能分配给 T[]
.
我经常使用as const
,因为它真的很强大,但我也经常在创建这样的元组时使用实用函数,但是不要想要将事物变成 readonly
个特定文字数组:
function tuple<T extends unknown[]>(...args: T): T { return args; }
(请注意,作为一个实际函数,这确实会引入运行时开销——as const
不会。但是它非常小。)
有了这个,我们就可以使用
tuple(tuple(1, 'foo'), tuple(2, 'bar'), tuple(3, 'baz'))
.forEach(([n, s]) => console.log(n * 3, s.toLocaleUpperCase()));
现在我们的数组是 [[number, string], [number, string], [number, string]]
,n
就是 number
,s
就是 string
。