如何使用类型中的属性为接口中属性的类型编制索引



我不知道这是否可能,甚至是可取的。我试图在类型中使用一个属性,对接口进行索引,并在接口中检索给定属性的类型。这有点难以描述,所以我想做的是:

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

伪接口:

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

然而,它不起作用。我想它不喜欢自引用,我也尝试使用this.propertyName

编辑:

szaman的回答很有帮助,完全按照我的要求做了。我只是没有意识到它不会像我想象的那样立即作为函数参数属性类型工作。我出于无知问了一个不完整的问题,这是我的错误。

以下是当前道具类型:

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 => {...}

现在的问题是,我需要指定函数组件在函数声明期间应键入的AppState的确切属性。错误如下:

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

我的目标是能够在AppState拥有的任何属性的其他地方使用此函数。TS会自动检测属性值的类型,并在options类型与给定属性值类型不匹配时警告我。

工作案例:

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

错误案例:

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

在第二个错误案例中,我的意图是让TS自动检测提供的选项数组值不等于AppState的propertyName"A"的类型。这样做可能吗?

当前类型的propertyNameoptions分别是可能的键和值的并集。但是,您需要为每个属性及其各自的选项创建一个顶级并集。这可以通过映射类型来完成,映射类型允许我们遍历键来创建新对象。然后,我们可以通过用keyof T访问这个新创建的对象来压平它,以获得{ propertyName, options }对象的可能组合的并集。

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游乐场链接

您可以使用带有约束的泛型类型来实现这一点。

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与我们的约束类型相匹配。

游乐场

最新更新