扩展索引类型的TypeScript接口

4
考虑一个简单的索引接口:
interface FormData {
    [K: string]: string;
}

那个小家伙工作得很好。但是,有一种情况下我想允许一个属性成为字符串数组。

interface AcmeFormData extends FormData {
    foobar: string[];
}

Typescript 发出以下警告:

属性 'foobar' 的类型为 'string[]',不能赋值给类型为字符串索引类型 'string'。

经过查阅文档,似乎以下代码是可以实现的,但同样会产生警告。

interface FormData {
    [K: string]: string;
    foobar: string[];
}

需要注意的是,我希望避免使用联合类型 ([K: string]: string | string[];),因为99%的情况下,数据都将是单个字符串值,因此希望避免使用类型提示。

这种情况是否可行?还是说我在试图滥用Typescript?

2个回答

4
这个代码无法运行的原因是[K: string]: string表示接口中每个键的值都必须是字符串,而foobar包含在每个键中。我建议改为以下方式:
interface FormData {
  fields: { [field: string]: string }
  somethingElse: string[]
}

有没有一种方法可以放松一下,使用 [field:string]:string|number,其中管道注释了一个假设的操作符,将两种类型合并在一起。这个问题能解决吗? - DonkeyBanana

4
您可以使用交集来实现这一点,而不是使用extends。例如:
interface FormData {
    [K: string]: string;
}

type AcmeFormData = FormData & { foobar: string[] };

declare const test: AcmeFormData;

test.foobar       // string[]
test.anythingelse // string

然而,这样做会引起一些问题,需要注意,因为现在索引签名不再准确。所以,当 TypeScript 使用该签名推断某些内容时,你需要意识到这将是错误的:

for (let key in test) {
    // val is inferred to have type string, but be careful!
    // In truth, val will be a string[] for the 'foobar' key,
    // but typescript is no longer aware of that. So this will
    // create a runtime error, but compiles without problems!

    const val = test[key].toLowerCase();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接