英文:
In Typescript, how to assign a member of a discriminated type union to a generic type which expects that union
问题
在TypeScript中,您可以使用类型断言来解决这个问题。要将FilterSet<FirstType>
分配给FilterSet<Union>
,您可以使用类型断言来明确告诉TypeScript编译器这是安全的。在您的InvokerComponent
中,您可以这样更改代码:
export const InvokerComponent = () => {
const getFilterSet: FilterSet<FirstType> = () =>
{targetField: "specificToFirst"}
const filterSet: FilterSet<FirstType> = getFilterSet();
return (
<Component filterSet={filterSet as FilterSet<Union>} />
)
}
通过使用as
关键字,您将filterSet
的类型断言为FilterSet<Union>
,这告诉TypeScript编译器这是安全的,因为FirstType
和SecondType
都是Union
的一部分。
这样应该解决了您遇到的类型错误问题。请注意,虽然这是一种解决方法,但要确保在使用类型断言时要谨慎,确保您了解代码的安全性。
英文:
I'm using React-Typescript. I have a component which takes props like so:
type ComponentPropsType = {
filterSet: FilterSet<Union>
}
type FilterSet<T> = {
targetField: keyof T;
}
type Union = FirstType | SecondType;
type FirstType = {
name: string;
id: number;
specificToFirst: string;
}
type SecondType = {
name: string;
id: number;
specificToSecond: string;
}
Here is the relevant portion of Component:
export const Component = ({ filterSet }: ComponentPropsType) => {
...
}
When I attempt to invoke this component like so:
export const InvokerComponent = () => {
const getFilterSet: FilterSet<FirstType> = () =>
{targetField: "specificToFirst"}
const filterSet: FilterSet<FirstType> = getFilterSet();
return (
<Component filterSet={filterSet} /> // TS ERROR HERE
)
}
Typescript tells me:
Type FilterSet<FirstType> is not assignable to type FilterSet<Union>
Type Union is not assignable to type FirstType
Type SecondType is missing the following properties from type FirstType: specificToFirst
My goal is to allow my component to accept a generic filterSet because I would like to restrict a field of filterSet to keyof the type passed in as the template. That's not displayed in my example above, but I don't think it's important to the problem at hand.
Once we make it into Component, I don't really care whether FirstType or SecondType was passed in to generate the filterSet. I want to restrict filterSet to FilterSet<Union>
because I want the Union types well defined. It's important to the definition of the filterSet, but not really the functionality of the component.
I hope I've given enough information to help solve this issue. To restate the question:
In Typescript, how do I assign a member of a discriminated type union to a generic type which expects that union.
答案1
得分: 1
问题是您的联合类型没有在FilterSet
中进行分发,这就是为什么FilterSet<Union
会被评估为:
{
targetField: "name" | "id";
}
实际上您需要的是以下格式的内容:
{
targetField: "name";
} | {
targetField: "id";
}
针对FirstType
和SecondType
特定字段不起作用的原因是keyof
操作符的已知问题(可能有一个GitHub问题,但我找不到)。
可以通过参考distributive conditional types docs来实现所需类型:
type FilterSet<T> = T extends T
? {
targetField: keyof T;
}
: never;
测试:
// type Result = {
// targetField: keyof FirstType;
// } | {
// targetField: keyof SecondType;
// }
type Result = FilterSet<Union>
这正是我们所需要的:
const getFilterSet = () => ({} as any);
export const InvokerComponent = () => {
// 以下函数简单返回一个类型为FilterSet<FirstType>的对象
const filterSet: FilterSet<FirstType> = getFilterSet();
return (
<Component filterSet={filterSet} /> // 没有错误
);
};
英文:
The issue is that your union is not being distributed in FilterSet
, which is why FilterSet<Union
is evaluated as:
{
targetField: "name" | "id";
}
What you actually need is something in the following format:
{
targetField: "name";
} | {
targetField: "id";
}
The reason why the fields that are specific for the FirstType
and SecondType
is a known issue with the keyof
operator (probably there is a GitHub issue, but I couldn't find one).
The desired type can be achieved by referring to distributive conditional types docs:
type FilterSet<T> = T extends T
? {
targetField: keyof T;
}
: never;
Testing:
// type Result = {
// targetField: keyof FirstType;
// } | {
// targetField: keyof SecondType;
// }
type Result = FilterSet<Union>
This is exactly what we need:
const getFilterSet = () => ({} as any);
export const InvokerComponent = () => {
// The following funcntion simply returns a an object of type FilterSet<FirstType>
const filterSet: FilterSet<FirstType> = getFilterSet();
return (
<Component filterSet={filterSet} /> // no error
);
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论