簡體   English   中英

映射類型+函數參數之謎

[英]Mapped types + function parameters enigma

下面的當前示例仍然無法完全滿足我的要求(示例:操縱redux reducers的函數)。 此函數輸出所需的類型,但允許不期望的輸入( c: 'hello' )。 在這里,似乎確實需要用到彎彎曲曲的技巧來按順序進行編譯。

type Reducer<State> = (s: State, p: any) => State

const reducerMap = <State>(s: State) => <
  ScopedReducers extends { [k in keyof State]: Reducer<State[k]> }
>(
  input: ScopedReducers
): { [k in keyof ScopedReducers]: Reducer<State> } => {
  return undefined as any
}

const state = { a: 1, b: "2" }
const mapped = reducerMap(state)({
  a: state => state + 1,
  b: state => state + "_",
  c: "hello",
})
  • ScopedReducers是一個與State有某種關系的對象(每個鍵都是Reducer<State[k]> ),但有自己的自由部分(reduceor有效負載)。 ScopedReducers僅應包含State也具有的鍵。
  • 如果我直接將ScopedReducers分配給它的約束,則其函數輸入將正確驗證。 如果我在State放置一個不存在的額外密鑰,則編譯器將按預期方式出錯。
    • 另一方面,構造函數返回值時,我無法重用Reducer的payload部分。 此類型將擦除為any
  • 如果我說ScopedReducers擴展了它的約束,那么它的類型不會被擦除,並且可以在組成動態映射函數返回時使用。
    • 另一方面,由於現在使用extends ,因此function參數現在接受無關的鍵(例如: e : 2 )。 關系驗證仍適用於適用的密鑰。

而且“真正的野獸”是此個人項目上此文件中文件的最后一個功能,它也存在一個“ keyof”問題,我認為可能無法解決...

不必過多擔心代碼中發生的事情,也不必擔心問題的ScopedReducers ,我認為您正在嘗試使ScopedReducers成為所謂的“ 精確類型” ,該類型 精確地包含指定的屬性:不少於不多。 不幸的是,這種類型在語言中尚不存在。 幸運的是,由於TypeScript 2.8中引入了條件類型 ,因此現在有一種方法可以要求類型參數的行為類似於精確類型,這是您所需要的。

讓我們介紹一下Exactify<T, X>

type Exactify<T, X extends T> = T & {
  [K in keyof X]: K extends keyof T ? X[K] : never
}

並想象一下Exactify<T, X>對於某個T Exactify<T, X>當泛型類型參數X約束為Exactify<T, X>時,會發生什么:

declare function exactlyFoo<X extends Exactify<Foo, X>>(x: X): void;

X extends Exactify<Foo, X>是什么意思? 如果X僅具有與Foo相同的鍵,則X extends Exactify<Foo, X>意味着僅X extends T & X ,也就是X extends T 但是,如果X甚至在Foo不存在一個鍵(例如extraKey ),則X extends Exactify<Foo, X>變為X extends T & X & { extraKey: never } ,除非屬性extraKey類型為never否則這是不可能的。 實際上,這意味着您無法添加額外的密鑰。

如果我將Exactify<>應用於您的代碼,它將變為:

const reducerMap = <State>(s: State) => <
  ScopedReducers extends Exactify<
  { [k in keyof State]: Reducer<State[k]> }, ScopedReducers>>(
    input: ScopedReducers
  ): { [k in keyof ScopedReducers]: Reducer<State> } => {
  return undefined as any
}

並使用它:

const state = { a: 1, b: "2" }
const mapped = reducerMap(state)({
  a: state => state + 1,
  b: state => state + "_",
  c: "hello", // error!
})

您在屬性c收到所需的錯誤。 希望能有所幫助。 祝好運!

暫無
暫無

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

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