簡體   English   中英

在 Typescript 泛型中對推斷的映射類型使用“擴展”

[英]Using "extends" on inferred mapped types in Typescript Generics

這是我的代碼和相關的游樂場

type SomeType<T> = {
  [K in keyof T]?: K extends 'u'
    ? string
    : T[K] extends object
      ? SomeType<T[K]>
      : object
}

function someType<T>(t: SomeType<T>) {
  return t;
}

type BLA = SomeType<{
  u: 1,
  b: {
    u: 1,
  },
}>;

const blaBLA: BLA = {
  u: 1, // <-- correct error msg: Type 'number' is not assignable to type 'string'.
  b: {
    u: 1, // <-- correct error msg: Type 'number' is not assignable to type 'string'.
  },
};

const bla = someType({
  u: 1, // <-- correct error msg: Type 'number' is not assignable to type 'string'.
  b: {
    u: 1, // <-- expected: error message from above
          // the problem here is that the value for b was resolved to 'object' instead of 'SomeType<T[K]>'
          // how can I fix this?
  },
});

我正在尋找解決我在上面代碼中描述的問題的方法,或者解釋為什么它不能按照我認為的方式工作。

因為這純粹是為了學習(理解)TS,所以我對任何一種結果都可以。

如果您有類似的功能

function someType<T>(t: SomeType<T>) {
  return t;
}

並用someType(val)調用它,然后編譯器將嘗試推斷泛型類型參數T假設valSomeType<T>類型。 您要求編譯器從本質上反轉類型函數SomeType<T>

但這對於編譯器來說是不可能的,尤其是因為SomeType<T>可能與SomeType<U>相同,即使TU不同:

type Hmm = SomeType<{ u: 1, b: "", c: { d: "" } }>;
/* type Hmm = {
    u?: string;
    b?: object;
    c?: {d?: object}
} */

type Ugh = SomeType<{ u: true, b: 123, c: { d: false } }>;
/* type Ugh = {
    u?: string;
    b?: object;
    c?: {d?: object}
} */

反轉類型函數並不總是可能的,或者即使可能,編譯器也不總是可行的。

幸運的是,這並不是您真正想要的行為。


相反,您似乎希望SomeType<T>充當T本身的遞歸約束 我的意思是,當您調用someType(val)時,您希望T被推斷為val的類型,然后您希望編譯器檢查T是否也可分配給SomeType<T>

所以讓我們直接把它寫成一個通用的約束

function someType<T extends SomeType<T>>(t: T) {
  return t;
}

編譯沒有錯誤,所以我們可以繼續測試它:

const bla = someType({
  u: 1, // error!
  b: {
    u: 1, // error!
  },
});

看起來不錯。 你得到的正是你期望得到的錯誤。

Playground 代碼鏈接

暫無
暫無

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

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