網站搜尋

typescript - 我可以逐步構建一個實現介面的物件嗎?


我有一個介面如下:

export interface Person {
  name: string;
  isMillenial: boolean;
}

以及一個輸出該介面的函數,如下:

function makePerson(name: string, birthYear: number): Person {
  let newPerson = {
    name
  }

  // Calculate various properties, slowly building up the `newPerson` object
  newPerson.isMillenial = birthYear < 1981

  return newPerson
}

但是這將會以如下錯誤失敗:

屬性 'isMillenial' 在類型 '{ name: string }' 中缺失,但在類型 'Person' 中是必需的。

我知道我可以在創建 newPerson 時聲明所有屬性,以符合預期——但是 我想逐步構建我正在創建的對象,逐漸添加屬性直到對象完整。 是否有辦法在 TypeScript 中逐步構建對象同時仍然滿足類型檢查?

(如果答案是「不,你需要預設值」,那也是可以接受的答案)

答案#1

是的,但你必須以不同的方式聲明它,並且你可能需要在完成對象時告訴 TypeScript。Partial 工具類型基於另一個類型創建一個類型,並使其所有屬性變為可選。所以:

function makePerson(name: string, birthYear: number): Person {
    let newPerson: Partial<Person> = {
    // −−−−−−−−−−−−^^^^^^^^^^^^^^^
        name
    };

    // Calculate various properties, slowly building up the `newPerson` object
    newPerson.isMillenial = birthYear < 1981;

    return newPerson as Person;
    // −−−−−−−−−−−−−−^^^^^^^^^
}

可惜最後的類型斷言是必要的(這讓我很驚訝,你可以從上面看出最終這兩個屬性都不會是 undefined,但 TypeScript 團隊不得不對編譯器的智能程度設置限制,以防它變得非常慢)。

遊樂場連結

返回上的 as Person 也意味著如果你願意,可以在函數宣告簽名中省略它,TypeScript 將會知道函數的返回類型:

function makePerson(name: string, birthYear: number): Person {
// Optional as far as TypeScript is concerned −−−−−−^^^^^^^^

...不過如果函數超過幾行,你可能會想保留它在那裡,以確保你不會在其他地方新增一個改變返回類型的 return。


你在問題中提到了它,但我還是要強調一下,僅僅是為了價值所在(以及給潛水者看),你可以先建立將要用來創建物件的資訊,然後一次性創建物件,這樣就不需要型別註解了。這樣確實會簡化示例,雖然當然實際程式碼可能不會變得更簡單:

function makePerson(name: string, birthYear: number): Person {
    const isMillenial = birthYear < 1981;
    return {name, isMillenial};
}

這並不總是可行,但當可行時,我覺得它很有用。