TypeScript:元素隐式具有 RegExp 的 'any' 类型
TypeScript: Element implicitly has an 'any' type for RegExp
所以,我想创建一个函数,它接受持续时间字符串(例如 12ms
、7.5 MIN
、400H
),解析它并将其转换为毫秒。
const units = {
MS: 1,
S: 1 * 1000,
MIN: 60 * 1 * 1000,
H: 60 * 60 * 1 * 1000
}
export function toMS(str: string): number {
let regex = /^(?<number>\d+(?:\.\d+)?)(?:\s*(?<unit>MS|S|MIN|H))?$/i
if (!regex.test(str)) {
throw new TypeError(`Expected a duration, got: ${str}`)
}
let match = str.match(regex)
let number = Number(match?.groups?.number)
let unit = (match?.groups?.unit || 'ms').toUpperCase()
return Math.floor(number * units[unit])
}
因此,函数 toMS()
接受一个字符串,测试提供的字符串是否有效 (number
+ whitespace (optional)
+ unit abbr (optional)
),如果有效 - 解析它使用 str.match(regex)
.
一切正常,直到:units[unit]
。它给了我一个错误:Element implicitly has an 'any' type because expression of type 'string' can't be used to index type
.
我之前在使用函数参数和 class 构造函数时遇到过同样的错误,由于用户提供了数据,所以很容易解决。但现在我不知道如何解决这个问题,因为我不能强制 str.match(regex).groups.unit
有一个像 : 'MS | S | MIN | H
.
这样的特定类型
我知道也可以用 "noImplicitAny": false
创建 tsconfig.json 但在我的情况下这根本不好。
问题在于 TypeScript 无法知道您的正则表达式是否真的匹配 MS|S|MIN|H
。这是 dependent types 领域,TypeScript 还没有那么强大。
TypeScript 唯一知道的是你匹配的是 string
,因为 match?.groups?.unit
和 'ms'
表达式都会产生 string
。
你可以做的是让 TypeScript 知道你的 units
是一个具有 string
类型的键和 number
类型的值的对象,并检查你是否匹配了是 units
对象上的 属性。像这样:
const units: { [k: string]: number } = { // letting TypeScript know
MS: 1,
S: 1 * 1000,
MIN: 60 * 1 * 1000,
H: 60 * 60 * 1 * 1000,
};
export function toMS(str: string): number {
const regex = /^(?<number>\d+(?:\.\d+)?)(?:\s*(?<unit>MS|S|MIN|H))?$/i;
if (!regex.test(str)) {
throw new TypeError(`Expected a duration, got: ${str}`);
}
const match = str.match(regex);
const number = Number(match?.groups?.number);
const unit = (match?.groups?.unit || 'ms').toUpperCase();
if (unit in units) { // checking whether your matched string is something you can handle, in runtime
return Math.floor(number * units[unit]);
} else {
throw new Error(`couldn't find units! :(`);
}
}
所以,我想创建一个函数,它接受持续时间字符串(例如 12ms
、7.5 MIN
、400H
),解析它并将其转换为毫秒。
const units = {
MS: 1,
S: 1 * 1000,
MIN: 60 * 1 * 1000,
H: 60 * 60 * 1 * 1000
}
export function toMS(str: string): number {
let regex = /^(?<number>\d+(?:\.\d+)?)(?:\s*(?<unit>MS|S|MIN|H))?$/i
if (!regex.test(str)) {
throw new TypeError(`Expected a duration, got: ${str}`)
}
let match = str.match(regex)
let number = Number(match?.groups?.number)
let unit = (match?.groups?.unit || 'ms').toUpperCase()
return Math.floor(number * units[unit])
}
因此,函数 toMS()
接受一个字符串,测试提供的字符串是否有效 (number
+ whitespace (optional)
+ unit abbr (optional)
),如果有效 - 解析它使用 str.match(regex)
.
一切正常,直到:units[unit]
。它给了我一个错误:Element implicitly has an 'any' type because expression of type 'string' can't be used to index type
.
我之前在使用函数参数和 class 构造函数时遇到过同样的错误,由于用户提供了数据,所以很容易解决。但现在我不知道如何解决这个问题,因为我不能强制 str.match(regex).groups.unit
有一个像 : 'MS | S | MIN | H
.
我知道也可以用 "noImplicitAny": false
创建 tsconfig.json 但在我的情况下这根本不好。
问题在于 TypeScript 无法知道您的正则表达式是否真的匹配 MS|S|MIN|H
。这是 dependent types 领域,TypeScript 还没有那么强大。
TypeScript 唯一知道的是你匹配的是 string
,因为 match?.groups?.unit
和 'ms'
表达式都会产生 string
。
你可以做的是让 TypeScript 知道你的 units
是一个具有 string
类型的键和 number
类型的值的对象,并检查你是否匹配了是 units
对象上的 属性。像这样:
const units: { [k: string]: number } = { // letting TypeScript know
MS: 1,
S: 1 * 1000,
MIN: 60 * 1 * 1000,
H: 60 * 60 * 1 * 1000,
};
export function toMS(str: string): number {
const regex = /^(?<number>\d+(?:\.\d+)?)(?:\s*(?<unit>MS|S|MIN|H))?$/i;
if (!regex.test(str)) {
throw new TypeError(`Expected a duration, got: ${str}`);
}
const match = str.match(regex);
const number = Number(match?.groups?.number);
const unit = (match?.groups?.unit || 'ms').toUpperCase();
if (unit in units) { // checking whether your matched string is something you can handle, in runtime
return Math.floor(number * units[unit]);
} else {
throw new Error(`couldn't find units! :(`);
}
}