簡體   English   中英

如何為 TypeScript 中的泛型類型編寫泛型輔助函數?

[英]How to write generic helper functions for a generic type in TypeScript?

我無法理解 TypeScript generics 與默認值的相互作用,以及如何盡可能廣泛地限制實用程序功能。 (這個例子是人為的,但它可以很容易地用少量的代碼來顯示問題。)

在建模一個簡單的案例時,你有一個給定“值”的“編輯器”,你可以這樣表達:

type Editor<V extends object = object> = {
    value: V
    set: (value: V) => void
}

編輯器是通用的,因此您可以進一步細化值的類型。 而且我已將默認值添加到通用參數,以便您可以更輕松地在不需要使其更具限制性的情況下省略它。

然后你有一個外部助手 function 被寫成通用的,可以與任何編輯器一起使用(簡化):

const get = <E extends Editor>(editor: E): E['value'] => {
    return editor.value
}

但是在嘗試為這些編輯器編寫工廠時,我遇到了 TypeScript 錯誤:

const create = <V extends object = object>(value: V): Editor<V> => {
    const editor: Editor<V> = {
        value,
        set: (value: V) => {
            const prev = get(editor)
            // ...
        }
    }

    return editor
}

錯誤是:

Argument of type 'Editor<V>' is not assignable to parameter of type 'Editor<object>'.
  Types of property 'set' are incompatible.
    Type '(value: V) => void' is not assignable to type '(value: object) => void'.
      Types of parameters 'value' and 'value' are incompatible.
        Type 'object' is not assignable to type 'V'.
          'object' is assignable to the constraint of type 'V', but 'V' could be instantiated with a different subtype of constraint 'object'.(2345)

為什么會這樣? 這令人困惑,因為get似乎盡可能寬松,所以我認為它會涵蓋所有子類型,但 TypeScript 仍然抱怨類型可能不匹配。

這是TypeScript 游樂場鏈接

原始游樂場的問題在這個游樂場中得到了解決,但我不知道我是否刪除了您正在探索的功能。

這段代碼可以編譯,我認為這將是做事的基礎......

type Editor<V extends object> = {
  value: V;
  set: (value: V) => void;
};

const get = <V extends object>(editor: Editor<V>): V => {
  return editor.value;
};

const create = <V extends object>(value: V): Editor<V> => {
  const editor: Editor<V> = {
    value,
    set: (value: V) => {
      const prev = get(editor);
      // ...
    },
  };

  return editor;
};

為了說明問題,您可以通過在操場上進行這些逐步更改來重新創建我的工作示例中的原始錯誤。

首先將get的簽名更改為此,它引入了一個潛在的縮小類型 E...

const get = <V extends object, E extends Editor<V>>(editor: E): V => {
  return editor.value;
};

然后通過確保縮小類型實際上正是編輯器實例的類型來修復它......

const prev = get<V,typeof editor>(editor);

...這澄清了與我沒有它的工作代碼相比,有一個額外的松散類型需要確定。

關於 Generics 和 Defaults 之間相互作用的未解決問題,因此您不是唯一一個。 我有一些啟發和學習...

A)如果類型是參數組合的一部分,請始終在包含該參數的 function 定義中包含該類型,消除任何地方的默認值,並且永遠不要默認為any

B)在實踐中,我發現 Typescript 幾乎總是從參數中推斷出類型,但前提是它們已通過遵循 A)保留,以便它們存在於 Typescript 的代碼路徑中進行檢查。

這可能解釋了為什么我對您的代碼的第一次干預是刪除默認值,第二次是確保對 Editor 的任何引用始終伴隨着可以從中推斷出的 Generic V。

哦,C)如果一個類型不需要別名(並且可能縮小),請不要添加縮小的“別名”,因為您可能會創建一個稍后發生沖突的別名。

因此,例如,如果 V 是能夠定義傳遞編輯器的 function 簽名所需的全部內容,那么不要創建別名E extends Editor<V> ,或者更糟糕的是E extends Editor ,這樣以后的簽名可能會意外地引入相當於別名E2 extends Editor<V2>可能是也可能不是同一件事。

暫無
暫無

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

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