簡體   English   中英

如何使用類型中的屬性來索引接口中屬性的類型

[英]How to use a property in type to index type of a property in an interface

我不知道這是否可能,甚至是否可取。 我正在嘗試使用類型中的屬性來索引接口並檢索接口中給定屬性的類型。 這有點難以描述,所以這就是我想要做的:

type Props = {
  propertyName: keyof AppState;
  options: AppState[propertyName];
};

虛擬界面:

export interface AppState {
  A: string;
  B: number[];
}

但是,它不起作用。 我假設它不喜歡自我引用,我也嘗試使用this.propertyName

編輯:

szaman 的回答非常有幫助,並且完全按照我的要求做了。 我只是沒有意識到它不會像我認為的 function 參數屬性類型那樣立即起作用。 我出於無知問了一個不完整的問題,我的錯誤。

這是目前的道具類型:

type Props<T extends keyof AppState> = {
  propertyName: T;
  // options is going to be an array of type of given propertyName values
  options: AppState[T][];
}

AppState 虛擬接口保持不變。 這是一個虛擬功能組件:

const MyComponent: React.FC<Props> = props => {...}

現在的問題是,我需要指定在 function 聲明期間應鍵入功能組件的 AppState 的確切屬性。 錯誤如下:

Generic type 'Props' requires 1 type argument(s).

我的目標是能夠將這個 function 與 AppState 擁有的任何屬性一起使用。 TS 會自動檢測屬性值的類型,並在options類型與給定屬性值的類型不匹配時警告我。

工作案例:

<MyComponent propertyName="A" options={["foo", "bar"]} />

錯誤案例:

<MyComponent propertyName="A" options={[0, 1]} />

在第二種錯誤情況下,我的意圖是讓 TS 自動檢測提供的選項數組值不等於 AppState 的 propertyName "A"類型。 這可能嗎?

您可以使用帶有約束的泛型類型來實現這一點。

type Props<T extends keyof AppState> = {
  propertyName: T;
  options: AppState[T];
};


let a: Props<"A"> = {
  propertyName: "A",
  options: "foo"
}

// this is invalid:
let aInvalidOptions: Props<"A"> = {
  propertyName: "A",
  options: [8, 9]
}

這里我們使用Props<T> ,它是泛型類型的特殊語法。 我們還對其添加了一個約束( type Props<T extends keyof AppState ),以便它只接受基於我們的AppState接口的類型。

然后我們使用傳遞的類型來確定options屬性的類型。 作為獎勵,我們甚至可以確保propertyName與我們的約束類型匹配。

操場

您當前的類型當前具有propertyNameoptions ,它們分別是可能的鍵和值的並集。 但是,您需要為每個屬性及其各自的選項創建一個頂級聯合。 這可以通過映射類型來完成,它允許我們遍歷鍵以創建一個新的 object。然后,我們可以通過使用keyof T訪問它來展平這個新創建的 object 以獲得{ propertyName, options }的可能組合的並集{ propertyName, options } object。

type Props<T> = {
  [K in keyof T]: { propertyName: K; options: T[K][] }
}[keyof T];

//   { propertyName: "hello"; options: string[]; }
// | { propertyName: "to"; options: number[]; }
// | { propertyName: "you"; options: string[]; }
type MyProps = Props<{
  hello: string;
  to: number;
  you: string;
}>;

const foo: MyProps = {
  propertyName: "hello",
  options: ["asdf"]
};

const foo2: MyProps = {
  propertyName: "to",
  options: [5, 3],
};

const foo3: MyProps = {
  propertyName: "hello",
  // @ts-expect-error It fails if you have an invalid option.
  options: ["asdf", 2]
};

const foo4: MyProps = {
  // @ts-expect-error It fails if you have an invalid name.
  propertyName: "not-a-valid-name",
  options: ["hey", 'you']
};

TypeScript 游樂場鏈接

暫無
暫無

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

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