TypeScript 高级类型对象键



我有一个具有以下签名的类Form

interface IFormSchema {
name: string;
// Removed irrelevant fields...
}
const schema: IFormSchema[] = [{ name: 'firstName' }];
// Form Interface
interface IForm {
fields: IFields;
// Removed irrelevant fields...
}
// Here is the IFields interface used in IForm
interface IFields {
// The key here is what I want typed **************
[key: string]: IField;
}
const form: IForm = new Form(schema: IFormSchema[]);

迭代架构数组,并使用IField接口将每个对象转换为Field


interface IField {
form: IForm;
name: string;
// Removed irrelevant fields...
}

现在,当我重新设置Form然后访问Form.fields,并且可以像form.fields.firstName一样按名称访问该字段时,我希望键入firstName,以便如果我尝试访问form.fields.wrongFieldName,TypeScript 将抛出错误。

我该怎么做?任何帮助将不胜感激。

这是可能的,但需要使用泛型类型和类型推断。如果您有像: IForm这样的显式类型注释,则没有什么可以允许一个IForm具有firstName字段而另一个IForm缺少该字段。

type IFormSchema<K extends string> = { name: K }
type IFields<K extends string> = Record<K, string>
class Form<K extends string> {
public fields: IFields<K>;
constructor(schema: readonly IFormSchema<K>[]) {
// initialise this.fields here
throw new Error('Not implemented');
}
}

用法示例:

// no type annotation, and must use `as const` to infer string literal types
const schema = [{name: 'firstName'}, {name: 'lastName'}] as const;
// no type annotation; allow the type argument K to be inferred
const form = new Form(schema);
let ok1: string = form.fields.firstName;
let ok2: string = form.fields.lastName;
let error: string = form.fields.address; // property 'address' does not exist

游乐场链接

这是不可能的。除非您在单独的记录类型中定义字段以将[key: string]定义为枚举或记录类型。

enum FieldsEnum = {
FIRST_NAME = 'firstName',
LAST_NAME = 'lastName',
};
type BaseFieldsType = {
// other fields here 
// and then the below 
[key in FieldsEnum]?: IField;
};
interface IFields extends BaseFieldsType {}; 

您只需要在 IFields 的键中指定它:

interface IFields {
firstName: IField;
}

事实上,如果您确定 IFields 中有哪些密钥可用,则可以摆脱索引签名并只使用密钥。

最新更新