[英]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
与我们的约束类型匹配。
您当前的类型当前具有propertyName
和options
,它们分别是可能的键和值的并集。 但是,您需要为每个属性及其各自的选项创建一个顶级联合。 这可以通过映射类型来完成,它允许我们遍历键以创建一个新的 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']
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.