如何在打字稿中定义一个常量数组
Posted
技术标签:
【中文标题】如何在打字稿中定义一个常量数组【英文标题】:How to define a const array in typescript 【发布时间】:2019-01-23 00:59:21 【问题描述】:我的代码:
const WEEKDAYS_SHORT: string[] = ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam']
错误信息来自 TypeScript (3.0) 编译器:
TS2322:类型 'string[]' 不可分配给类型 '[string, string, string, string, string, string, string]'。 “字符串[]”类型中缺少属性“0”。
如果我把string[]
改成ReadonlyArray<string>
,那么错误信息就变成了:
TS2322:类型“ReadonlyArray”不可分配给类型“[string, string, string, string, string, string, string]”。 “ReadonlyArray”类型中缺少属性“0”。
我的 tsconfig.json:
"compilerOptions":
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es6", "dom"],
"module": "es6",
"moduleResolution": "node",
"sourceMap": true,
"target": "es5",
"jsx": "react",
"strict": true
,
"exclude": [
"**/*.spec.ts",
"node_modules",
"vendor",
"public"
],
"compileOnSave": false
如何在 TypeScript 中定义只读数组?
【问题讨论】:
无法重现您的错误,即使使用strict: true
。 typescriptlang.org/play/…
嘿 @TitianCernicova-Dragomir 我添加了 tsconfig.json
【参考方案1】:
调试后发现不是TypeScript编译器的问题,是因为我使用了第三方组件调用DayPicker:
<DayPicker
onDayClick=this.handleDayClick
selectedDays=posts.day
months=MONTHS
weekdaysShort=WEEKDAYS_SHORT
firstDayOfWeek=1/>
道具weekdaysShort
的类型不是string[]
,而是[string, string, string, string, string, string, string]
weekdaysShort?: [string, string, string, string, string, string, string];
所以 TS 编译说 string[]
与 [string, string, string, string, string, string, string]
不匹配。
最后,我只是将类型从string[]
更改为any
以避免出现此错误消息,当然我们也可以更改为[string, string, string, string, string, string, string]
(太长)。
【讨论】:
在这种情况下,我发现自己在进行类型定义,并使用该类型。即type WeekdaysShort = ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam']
。然后,const WEEKDAYS_SHORT: WeekdaysShort = ...
【参考方案2】:
正如您指出的那样,问题是因为您尝试将字符串数组 (string[]
) 分配给 7 字符串元组。虽然您使用any
的解决方案会起作用,但通常不建议使用any
。拼出柔顺也不太理想,因为它太长了。
我们可以做的是创建一个辅助函数来创建一个元组类型。这个函数可以在任何你需要元组的地方重复使用:
function tupleArray<T extends any[]>(...v: T)
return v;
const WEEKDAYS_SHORT_INFFERED = tupleArray('Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam') // INFFERED AS [string, string, string, string, string, string, string]
const WEEKDAYS_SHORT: [string, string, string, string, string, string, string] = WEEKDAYS_SHORT_INFFERED
【讨论】:
它有效!神奇!最后一行可以简化为const WEEKDAYS_SHORT = WEEKDAYS_SHORT_INFFERED
@Spark.Bao 我的观点是对预期元组的变量的可分配性,类型只是为了证明这一点:)【参考方案3】:
我没有在TypeScript playground 上重现该问题。
但是,不管它是什么(字符串数组string[]
或7 字符串元组[string, string, string, string, string, string, string]
),使用推断类型怎么样?
const WEEKDAYS_SHORT = ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'];
const sunday = 0;
const dayShortName = WEEKDAYS_SHORT[sunday]; // => 'Dim'
还是枚举?
enum WEEKDAYS_SHORT 'Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'
const sunday = 0;
const dayShortName = WEEKDAYS_SHORT[sunday]; // => 'Dim'
IMO,在这种情况下,上述两个选项都比指定类型 any
更好。
【讨论】:
【参考方案4】:断言你的数组声明as const
;
const readonlyArray = [1, 2, 3] as const;
此外,访问readonly
数组的元素类型很简单:
type Element = typeof readonlyArray[number]` // 1 | 2 | 3
as const
断言适用于任何声明,包括对象和深度嵌套的数据结构。您甚至可以断言表达式as const
。例如,如果值1
被推断为number
,但您想提供数字文字类型,只需将其声明为1 as const
。
该功能是在 TypeScript 3.4
中引入的。也可以参考the docs。
请注意,readonly
或 const
数组通常称为元组(在 Python 中就是这种情况 - reference)。元组可以具有相同类型的元素或完全不同类型的元素。请注意,在上面的示例中,Element
类型没有被推断为number
,而是作为数字文字的联合。这是可能的,因为元组的元素永远不会改变。推断最窄的可能类型是实用的。例如,您可以在需要number
的任何地方使用数字文字类型1
,但不能在需要数字文字类型1
的地方使用number
类型。
两个元素的元组通常称为一对,可以表示为一个产品。虽然[number, string]
的乘积不是数字,但您仍然可以将它们相乘。因为string
和number
本身都是无限大的,所以它们的产品类型也是无限大的。考虑[1 | 2 | 3, 'a' | 'b' | 'c']
的更简单示例,它等于:
[1, 'a']
| [1, 'b']
| [1, 'c']
| [2, 'a']
| [2, 'b']
| [2, 'c']
| [3, 'a']
| [3, 'b']
| [3, 'c']
进一步阅读:
readonly and const Product Types【讨论】:
【参考方案5】:虽然接受的答案是正确的,但它确实有一个缺点。
const readonlyArray = [1, 2, 3] as const;
let x = 4; // function parameter, etc.
// Argument of type 'number' is not assignable to parameter of type '1 | 2 | 3'.ts(2345)
// if (readonlyArray.includes(x))
另一种方法是使用readonly
:
const readonlyArray: readonly number[] = [1, 2, 3];
let x = 4;
if (readonlyArray.includes(x)) // OK
// Property 'push' does not exist on type 'readonly number[]'.ts(2339)
// readonlyArray.push(4);
【讨论】:
以上是关于如何在打字稿中定义一个常量数组的主要内容,如果未能解决你的问题,请参考以下文章