簡體   English   中英

如何轉換或更改 TypeScript 中的通用類型?

[英]How can I cast or change the generic type in TypeScript?

function cast<R, T>(v: T): R {
  return v as R;
         ~~~~~~
         // Error
}

所以我要做的是將v的類型從 T 更改為 R。但是,我看到以下錯誤。

Conversion of type 'T' to type 'R' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  'T' is assignable to the constraint of type 'R', but 'R' could be instantiated with a different subtype of constraint '{}'.

使用InstanceType<typeof R>也會給我一個錯誤。 有人知道怎么做嗎?

TypeScript 的類型斷言,形式expr as Type ,允許您告訴編譯器表達式expr屬於特定類型Type 編譯器通常會很好地確定表達式應該是什么類型,但有時開發人員知道一些編譯器不知道的內容,這就是您告訴編譯器的方式。

請注意, expr as Type沒有任何運行時效果。 大多數情況下,出現在 TypeScript 中的類型僅僅描述了在運行時預期發生的事情; 他們不會改變發生的事情。 static 類型系統基本上從實際運行的 JavaScript 中刪除

因此, expr as number是編譯時類型斷言而不是運行時類型轉換 例如,它不會執行像0+expr這樣的類型強制或像Number(expr)這樣的類型轉換


好的,類型斷言讓我們告訴編譯器它應該將表達式視為什么類型。 但是編譯器不會毫無怨言地自動接受所有這些斷言。 通常,如果它已經認為表達式可分配給該類型,它將允許斷言:

const foo = "foo" as string; // okay, widened from "foo" to string

您可以將其視為“向上轉換”,但最好將其描述為“擴大”。 如果它認為表達式可能是該類型,它也將允許斷言,因為斷言類型可分配給它:

let bar = (Math.random() < 99 ? "bar" : 1) as string; 
// okay, narrowed from string | number to string

您可以將其視為“向下轉換”,但最好將其描述為“縮小范圍”。 這些規則並不是全部,但一般的想法是,如果它們正在擴大或縮小,編譯器將允許斷言。


編譯器對它認為既不擴大也不縮小的斷言猶豫不決。 如果它認為您正在采用X類型的表達式並斷言它是Y類型,並且如果XY都不能分配給另一個,那么這些類型不會彼此“充分重疊”,您可能正在做類型斷言錯誤。 兩個未指定的泛型類型參數TR就是這種情況。 如果T extends RR extends T為真,那很好,但就目前而言,它們可能是完全不相關的類型,因此斷言被阻止:

function castBad<R, T>(v: T): R {
    return v as R; // error!
    // --> ~~~~~~
    // Conversion of type 'T' to type 'R' may be a mistake because 
    // neither type sufficiently overlaps with the other.
    // If this was intentional, convert the expression to 'unknown' first.
}

錯誤消息為您提供了成功所需的提示:對范圍很廣或范圍很窄的內容進行中間類型斷言,以使編譯器將每個步驟視為相關。 所有類型都可分配給unknown類型,因此您可以將其用作中間類型:

function cast<R, T>(v: T): R {
    return v as unknown as R; // okay
}

使用v as unknown你正在擴大Tunknown ,然后使用(v as unknown) as R你正在縮小unknownR 您還可以使用以下任何一項:

v as never as R; // narrow to never, widen back to R
v as any as R; // narrow/widen to any, narrow/widen back to R
v as (T | R) as R; // widen to the union, narrow back to the other member
v as (T & R) as R; // narrow to the intersection, widen back to the other member

所以,這應該有效。 我擔心像cast()這樣的 function 的用例,因為它只是一個偽裝成 function 的類型斷言,因此也有同樣的警告,即不是人們通常所說的“演員表”:

const x = cast<number, string>("hello");
console.log(x.toFixed(1)); // okay at compile time, error at runtime.  oops

此外,如果您真的想要類型斷言 function,那么T泛型參數不會做太多繁重的工作; 它必須手動指定,但可以通過您傳入的參數合理地推斷出來。事實上,由於它僅用於參數的類型,您可以完全消除它:

function typeAssert<R>(v: any): R {
    return v;
}

然后當你使用它時,你只需要指定所需的返回類型:

const y = typeAssert<string>(Math.random() < 99 ? "okay" : 123); // string

游樂場代碼鏈接

暫無
暫無

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

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