2017-09-15 118 views
1

我有一個Column接口,可以使基於該鍵的行值:如果我明確地設置每個列的類型打字稿:執行一致的對象鍵類型參數

interface Column<Row, Field extends keyof Row> { 
    key: Field; 
    render: (value: Row[Field]) => React.ReactNode; 
} 

,然後我得到了想要的行爲。例如,以下是無效的:

interface User { 
    id: number; 
    name: string; 
} 

const column: Column<User, "id"> = { 
    key: "id", 
    render(id: string) { 
     return id; 
    } 
}; 

因爲id屬性是一個字符串,而不是數字。有沒有辦法獲得這種行爲,而不必單獨指定每個列的類型?例如,以下類型的檢查:

const columns: Array<Column<User, keyof User>> = [ 
    { 
     key: "id", 
     render(id: string) { 
      return id; 
     } 
    } 
]; 

因爲Field被實例化到keyof User,而不是一個特定的鍵。

+0

工會類型如何: id:number |串; 看看: https://stackoverflow.com/questions/38628115/what-does-the-pipe-mean-in-typescript – proti

+0

我不知道這有什麼幫助:我希望TypeScript只允許'ID:數字「作爲參數。 –

+0

哦,好的。雖然不理解你的問題。 – proti

回答

1

啊,我喜歡這種類型的問題。你遇到的一個問題是,TypeScript不會讓你遺漏類型參數和infer their types。你想說一些類似於Column<User>的地方,其中類型參數是從你傳遞給它的對象字面量推斷出來的。好了,我們不能這樣做直接......但我們可以間接得到這樣的效果:

function columnsFor<Row>() { 
    function of<Field extends keyof Row>(column: Column<Row, Field>): Column<Row, Field> { 
    return column; 
    } 
    return of; 
} 

功能columnsFor是不大不小的curried功能;您可以明確設置類型參數,並且它返回另一個函數,該函數接受Column<Row,Field>對象任意有效類型Field。這裏是你如何使用它:

const userColumn = columnsFor<User>();  

const goodColumn = userColumn({ 
    key: "id", 
    render(id: number) { 
    return id; 
    } 
}); // ok, inferred as Column<User, "id"> 

const badColumn = userColumn({ 
    key: "id", 
    render(id: string) { 
    return id; 
    } 
}); // error as expected 

userColumn功能將只接受一些Column<User, Field>類型的參數,並從這樣的說法推斷Field。現在,您可以繼續製作該陣列:

const columns = [ 
    userColumn({ 
    key: "id", 
    render(id: number) { 
     return id; 
    } 
    }), // ok, inferred as Column<User,"id"> 
    userColumn({ 
    key: "name", 
    render(name: string) { 
     return name; 
    } 
    }), // ok, inferred as Column<User,"name"> 
    userColumn({ 
    key: "id", 
    render(id: string) { 
     return id; 
    } 
    }) // error as expected 
]; 

希望對您有用。祝你好運!

+0

謝謝,我懷疑這樣做可能是可能的,但我不確定TypeScript中的慣用方法是什麼。我希望有一種方法可以保證使用類型系統的正確使用,因爲它仍然有可能產生不正確的代碼。如果TypeScript通過使'Column'不透明來實現不透明類型,那麼所有列都必須使用'columnFor'來創建。 –

+0

你可以使用一個私有構造函數使'Column'成爲一個類,並給它一個靜態方法來產生所需的'Column'對象。上面的代碼並不完全錯誤;你告訴TypeScript你需要一個'Column '的數組,這實際上不是你的意思。 – jcalz

+0

謝謝,我會看看私人構造函數。至於原始代碼沒有錯誤:我認爲這個列不是'Column '的有效實例,因爲'render'方法不能處理這兩種情況。我認爲唯一的因爲類型檢查是由於TypeScript的(不完備的)雙變量函數參數。 –