打字稿:强制执行现有的对象键

typescript: enforcing existing object keys

我希望 dropdownAttributes 仅限于 DropDownItem 接口上的属性。

interface DropDownItem {
    [key: string]: any;
}
interface Props {
   dropdownList: DropDownItem[];
   dropdownAttributes: string[];
}

如果 DropDownItem 现在有动态属性,我想我可以用 keyof 解决这个问题,像这样:

interface Props {
   dropdownList: DropDownItem[];
   dropdownAttributes: (keyof DropDownItem)[];
}

但这对我来说现在不起作用。如何解决?

如果键在界面中定义为 [key: string]: value,则无法提供 keyof,因为这意味着几乎可以有任何键。

因此,此 keyof DropDownItem 代码 returns string | number,因为这些是 key 可以具有的值。

您可以通过为对象接口定义特定键来避免这种情况:

interface DropdownItem {
   id: number,
   text: string,
   isDisplayed: boolean,
}

interface Props {
   dropdownList: DropdownItem[],
   dropdownAttributes: (keyof DropdownItem)[] // ("id" | "text" | "isDisplayed")[]
}

您似乎希望 Props 是通用的,以便它可以被不同的对象类型使用。这可以通过在 Props

中定义泛型类型 T 来实现
interface Props<T> {
   dropdownList: T[];
   dropdownAttributes: (keyof T)[];
}

现在,如果我们事先知道某个对象的类型,我们可以为它创建一个接口,并在 Prop

中创建一个使用该接口的类型
interface MyDropDownItem {
  foo : number
}

type MyDropDownItemProps = Props<MyDropDownItem>;

我们现在只能在 dropdownList 中使用 MyDropDownItem 的实例及其在 dropdownAttributes

中的键
const good: MyDropDownItemProps = {
  dropdownList: [{foo: 2}],
  dropdownAttributes : ['foo']
}

const bad: MyDropDownItemProps = {
  dropdownList: [{foo: 2, bar: 's' /* error here */}],
  dropdownAttributes : ['foo', 'bar' /* and here */ ]
}

这当然假设您事先知道下拉菜单的结构,因为这是打字稿唯一可以帮助您的。 Typescript 不会帮助您确保运行时类型安全。

Check it out on stackblitz

最后我做到了。

interface Props<T> {
   dropdownList: T[];
   dropdownAttributes: (keyof T)[];
}

declare class MyComponent<T> extends React.Component<Props<T>> {}

export default MyComponent;

用法:

interface DropdownItem {
   key1: string;
   key2: string;
}

<MyComponent
   <DropdownItem>
   dropdownAttributes={['key1', 'key2']}
   dropdownList={[{key1: 'hello', key2: 'world'}]}       
/>