簡體   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