繁体   English   中英

从另一个对象的值推断类型键

[英]Infer a type key from another object's values

我有一个界面专栏。

interface column {
  field: string
  label: string
}

所以一行列将是:

const cols = [{
    label: 'First Name',
    field: 'fname',
  },
  {
    label: 'Last Name',
    field: 'lname',
  },
  {
    label: 'Email',
    field: 'email',
  }]

数据将是一组数据行。

const data:{}[] = [{
fname: 'bob', lname: 'dylan', email: 'db@email.com',
fname: 'van', lname: 'halen', email: 'vh@email.com'
}]

有没有办法强制数据的键,即 [fname, lname, email] 是相应 cols[n]['field'] 的值? 提前致谢。

是的,只要您以这样的方式定义cols以使编译器不会将field属性扩大到string ,您就可以这样做。 使用 TS3.4+ 最简单的方法是使用const断言

const cols = [{
  label: 'First Name',
  field: 'fname',
},
{
  label: 'Last Name',
  field: 'lname',
},
{
  label: 'Email',
  field: 'email',
}] as const;

as const意味着cols将被视为只读元组,其中labelfield属性具有字符串文字类型。

从那里您可以创建一个类型别名,将一组与Column兼容的值转换为 object 类型,并将field属性作为键。 当然没有提到每个字段的值类型应该是什么,所以我假设它总是string

interface Column {
  field: string
  label: string
};

type StringObjFromColumns<T extends readonly Column[]> =
  { [K in T[number]["field"]]: string }

然后我们可以将您的数据类型定义为StringObjFromColumns<typeof cols>

const data: StringObjFromColumns<typeof cols>[] = [{
  fname: 'bob', lname: 'dylan', email: 'db@email.com',
}, {
  fname: 'van', lname: 'halen', email: 'vh@email.com'
}, {
  fname: 'van', lname: 'morrison', age: 75, email: 'vm@example.com' // error! age is extra
}, {
  fname: 'ted', lname: 'nugent' // error! email is missing
}]

您可以看到它如何强制每个 object 必须具有这三个类型为string的字段的约束。

好的,希望有帮助; 祝你好运!

Playground 代码链接

这是不可能的,因为 typescript 类型是在编译时而不是运行时强制执行的。 请参阅我对这个问题的回答,它回答了你的问题。

这是一个棘手的问题。

interface Column {
    field: string
    label: string
}

我们可以定义一个RowObject ,另外,为了举例,一个Row具有column属性和row本身。

interface RowObject {
    [key: string]: string;
}

interface Row {
    cols: Column[];
    object: RowObject;
}

现在,我们应该定义一个 function 来制作新对象的原型。

const createRowBlueprint = (cols: Column[]): Row => {
    return {
        cols: [...cols],
        object: cols.map(c => c.field)
                    .reduce((prop: RowObject, prev: string) => (prop[prev] = '', prop), {})
    };
};

我刚刚定义了Row接口来动态访问“真正的行对象”属性,就像这样

const row = createRowBlueprint(cols);
row.cols.forEach(col => {
    const { field } = col;
    const value = row.object[field];
    console.log(`Field ${field} binded to ${value}`);
});

给定您的columns集合,这将输出以下内容

{
  cols: [
    { label: 'First Name', field: 'fname' },
    { label: 'Last Name', field: 'lname' },
    { label: 'Email', field: 'email' }
  ],
  row: { fname: '', lname: '', email: '' }
}

Field fname binded to
Field lname binded to
Field email binded to

显然,我将默认值设置为空字符串。 但是,它有效的证明是从该字段访问的值不是undefined

最后,这种方法不是安全类型的。 但是,据我所知,Typescript 暂时不支持编译时的动态类型定义......所以这是一个棘手的解决方法。

希望能帮助到你。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM