我正在为我不控制的库编写类型声明文件。其中一种方法接受字符串数组作为参数,但是这些字符串只能是非常特定的值。目前,我正在以string[]
形式输入此参数,但我想知道是否有一种方法可以增强此参数以使其包括特定值。
示例来源(我无法更改):
Fruits(filter) {
for (let fruit of filter.fruits)
{
switch(fruit)
{
case 'Apple':
...do stuff
case 'Pear':
...do stuff
default:
console.error('Invalid Fruit');
return false;
}
}
return true;
}
我当前的类型声明:
function Fruits(filter: FruitFilter): boolean;
interface FruitFilter {
fruits: string[];
}
在撰写此问题时,我提出了一个部分解决方案,方法是定义有效字符串的联合类型,然后将字段类型设置为该联合的数组而不是字符串数组。这给了我想要的检查,但是我注意到,如果输入无效的字符串,则会将数组中的所有字符串标记为无效,并显示错误Type 'string' is not assignable to type 'Fruit'
。有没有更好的方法可以做到,这样仅将有问题的字符串标记为无效字符串,或者将其标记为接近我要得到的字符串?
部分解决方案:
function Fruits(filter: FruitFilter): boolean;
type Fruit = 'Apple' | 'Pear'
interface FruitFilter {
fruits: Fruit[];
}
答案 0 :(得分:3)
所以,您的问题似乎是这样的:
type Fruit = "Apple" | "Pear";
interface FruitFilter {
fruits: Fruit[];
}
declare function Fruits(filter: FruitFilter): boolean;
Fruits({ fruits: ["Apple", "Apple", "Pear"] }); // okay
Fruits({ fruits: ["Apple", "App1e", "Pear"] }); // error
// actual error: ~~~~~~~ ~~~~~~~ ~~~~~~ <-- string not assignable to Fruit
// expected error: ~~~~~~~ <-- "App1e" not assignable to Fruit
不是您有一个错误,而是错误没有适当地限制在数组的“坏”元素上。
我对发生这种情况的猜测是,编译器倾向于将字符串文字扩展为string
,将元组类型扩展为数组,除非您给出提示不要这样做。因此,当无法验证fruits
的类型为Fruit[]
时,它将备份并查看您提供的内容。它将["Apple", "App1e", "Pear"]
扩展为string[]
(忘记了字符串文字和它是一个三元素元组的事实),意识到string[]
不可分配给Fruit[]
,然后通过标记每个元素来警告您。我对GitHub issues进行了简短搜索,以查看是否有过报告,但是我还没有看到。可能值得提出一些东西。
无论如何,为了检验我的猜测,我决定更改Fruits()
的声明,以暗示我们尽可能要一个字符串文字元组。请注意,[目前尚无方便的方法];现在提示的方法是炼金术:
// ⚗❓
declare function Fruits2<S extends string, T extends S[] | [S]>(arr: {
fruits: T & { [K in keyof T]: Fruit };
}): boolean;
Fruits2({ fruits: ["Apple", "Apple", "Pear"] }); // okay
Fruits2({ fruits: ["Apple", "App1e", "Pear"] }); // error
// ~~~~~~~ <--string is not assignable to never
好吧,尽管该消息可能仍然令人困惑,但该错误的位置仍然是您想要的位置。当编译器尝试将"Apple"
分配给不存在的交点Fruit & "App1e"
时,就会发生这种情况。编译器正确地将Fruit & "App1e"
减小为never
...,但可能为时过早,以致错误消息不起作用。
无论如何,我不推荐这种“解决方案”,因为它要复杂得多,并且在错误情况下只能为您提供更好的错误体验。但这至少是关于发生原因的答案,以及解决该问题的可能方向(例如查找或提出问题的可能方向)。好的,祝你好运!
答案 1 :(得分:1)
您也可以为此使用枚举:
enum Fruits {
Apple,
Pear,
}
interface FruitFilter {
fruits: Array<Fruits>;
}
这些将用纯Javascript转换为0和1。
如果需要,您也可以使用字符串而不是数字。然后,您必须像这样定义枚举:
enum Fruits {
Apple = 'Apple',
Pear = 'Pear',
}
TypeScript文档还有更多示例,以及如何在运行时使用它:
https://www.typescriptlang.org/docs/handbook/enums.html#enums-at-runtime