網站搜尋

根據 Typescript 中兄弟屬性的泛型類型推斷類型


我想根據其同級屬性的泛型類型來定義一個屬性的類型。

例如,假設我們有:

type Person = {
  id: number;
  name: string;
}

type Select<Value=unknown> = (props:Props<Value>) => any;

const PersonSelect:Select<Person> = (props) => null //implementation is irrelavant
const TextSelect:Select<string> = (props) => null //implementation is irrelavant


那麼我想要能夠做像這樣的事情:

type Filter<V = unknown > = {
  component: Select<V>,
  transformer: (value: V) => string
};

const filters:Array<Filter> = [
  {
    component: PersonSelect,
    transformer: (selected) => selected.name //type of `selected` should be infered as `Person`
  },
  {
    component: TextSelect,
    transformer: (selected) => selected // type of `selected` should be infered as `string`
  }
]


變通方法

使用上述代碼,我可以這樣做


const personFilter:Filter<Person> = {
    component: PersonSelect,
    transformer: (selected) => selected.name
}
const textFilter:Filter<string> = {
    component: TextSelect,
    transformer: (selected) => selected
}

const filters = [personFilter, textFilter];

但我正在尋找一種不需要明確定義每個過濾器對象類型的解決方案。此外,泛型 V 類型可以是任何類型,所以我無法使用所有可能組合的聯合。

有沒有更好的解決方案?

答案#1

似乎是 TypeScript 在根據同一對象的其他屬性推斷箭頭函數屬性參數時遇到了困難。

我無法借助函數推斷來完成它。

最簡單的方法是建立一個 builder 函數,該函數返回 Filter<_>。

type Person = {
  id: number;
  name: string;
}

type Props<T> = T

type Select<Value = unknown> = (props: Props<Value>) => any;

const PersonSelect: Select<Person> = (props) => null //implementation is irrelavant

const TextSelect: Select<string> = (props) => null //implementation is irrelavant

type Filter<V = unknown> = {
  component: Select<V>,
  transformer: <T extends V>(value: T & V) => string
};


const builder = <V,>(
  component: Select<V>,
  transformer: (value: V) => string
): Filter<V> =>
  ({ component, transformer })

const filters = [
  builder(PersonSelect, (selected) => selected.name),
  builder(TextSelect, (selected) => selected)
]

遊樂場

因為 component 和 transformer 參數不是同一個資料結構的一部分,所以推斷它們並應用我們的類型約束會更容易。

在這裡,你可以找到更多關於函數參數型別推斷的例子。