簡體   English   中英

為什么 Typescript 不要求我的 function 返回某個類型?

[英]Why isn't Typescript requiring my function to return a certain type?

我有一個通用的Factory function 應該返回一個特定的類型:

type Factory<T> = () => T;

interface Widget {
  creationTime: number;
}

const build: Factory<Widget> = () => {
  return {
    creationTime: Date.now(),
    foo: 'bar',
  };
};

我希望 Typescript 會拋出錯誤,因為foo不是接口 Widget 上的屬性。 但是,事實並非如此。

但是,如果我將widgetFactory function 修改為以下代碼——唯一的區別是我明確聲明了返回類型——那么它確實會引發錯誤:

const build: Factory<Widget> = (): Widget => {
  return {
    creationTime: Date.now(),
    foo: 'bar',
  };
};

有沒有辦法讓 Typescript 為我的通用Factory類型分配相同的“嚴格性”?

TypeScript 中的 Object 類型通常不禁止額外的屬性。 它們是“開放的”或“可擴展的”,而不是“封閉的”或“精確的”(參見microsoft/TypeScript#12936 )。 否則就不可能使用子類或接口擴展:

interface FooWidget extends Widget {
   foo: string;
}
const f: FooWidget = { creationTime: 123, foo: "baz" };
const w: Widget = f; // okay

有時人們想要這樣的“精確”類型,但它們並不是語言的一部分。 相反,TypeScript 有多余的屬性檢查,這僅在非常特殊的情況下發生:當“新鮮” object 文字被賦予不知道 ZA8CFDE6331BD59EB2AC966F8911C4 中的某些屬性的類型時:

const x: Widget = { creationTime: 123, foo: "baz" }; // error, what's foo

如果 object 文字尚未分配給任何類型,則它是“新鮮的”。 xw之間的唯一區別是,在x中,文字是“新鮮的”,並且禁止使用過多的屬性,而在w中,文字是……呃……“陳舊”,因為它已經被賦予了FooWidget類型。


由此看來,您的widgetFactory似乎應該給出一個錯誤,因為您正在返回 object 文字而沒有在任何地方分配它。 不幸的是,在這種情況下失去了新鮮感。 有一個長期存在的問題microsoft/TypeScript#12632指出了這一點,並且取決於一個非常古老的問題microsoft/TypeScript#241 TypeScript 在檢查它是否與預期的返回類型兼容時會自動擴大返回的類型......並且會丟失新鮮度。 看起來沒有人喜歡這個,但很難在不破壞其他東西的情況下修復它 所以現在,它就是這樣。


您已經有了一種解決方法:顯式注釋函數的返回類型。 這不是特別令人滿意,但它完成了工作。

export const WidgetFactory1: Factory<Widget> = {
   build: (): Widget => {
      return {
         creationTime: Date.now(),
         foo: 'bar', // error!
      };
   },
};

其他涉及嘗試強制編譯器計算精確類型的解決方法是可能的,但比你正在做的要丑得多:

const exactWidgetFactory =
   <W extends Widget & Record<Exclude<keyof W, keyof Widget>, never>>(
      w: Factory<W>) => w;

export const WidgetFactory2 = exactWidgetFactory({
   build: () => { // error!
// ~~~~~ <-- types of property foo are incompatible
      return {
         creationTime: Date.now(),
         foo: 'bar',
      };
   },
});

因此,我建議您繼續使用您所擁有的內容。


好的,希望有幫助; 祝你好運!

Playground 代碼鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM