I have the following code:
我有以下代码:
type XType<T> = {
x: T;
};
function extractTypes<Props, T>(Component: React.FC<Props & XType<T>>) {
return (props: Props, value: T) => {
Component({ ...props, x: value });
};
}
const CompA: React.FC<{ a: string } & XType<string>> = () => <div>HELLO</div>;
const CompB: React.FC<{ b: string } & XType<number>> = () => <div>WORLD</div>;
extractTypes<{ a: string }, string>(CompA)({ a: 'A' }, 'X'); // OK
extractTypes<{ b: string }, number>(CompB)({ b: 'B' }, 1); // OK
extractTypes(CompA)({ a: 'A' }, 'X'); // Compile error
extractTypes(CompB)({ b: 'B' }, 1); // Compile error
CompA
and CompB
expect a
and b
properties along with all properties in XType
.
CompA和CompB需要a和b属性以及XType中的所有属性。
The 3rd-last and 4th-last compile correctly, however the Typescript compiler complains on the last two lines as follows:
倒数第三行和倒数第四行编译正确,但TypeScrip编译器在最后两行报告如下:
Argument of type '{ a: string; }' is not assignable to parameter of type 'PropsA & XType<string>'.
Property 'x' is missing in type '{ a: string; }' but required in type 'XType<string>'.ts(2345)
Argument of type '{ b: string; }' is not assignable to parameter of type '{ b: string; } & XType<number>'.
Property 'x' is missing in type '{ b: string; }' but required in type 'XType<number>'.ts(2345)
I've tried many approaches to ensure that I can call extractTypes
without specifying the types explicitly and still ensure that the method returned by this function accepts only { a: string }
or { b: string }
instead of { a: string; x: string }
or { b: string; x: number }
, but to no avail.
我尝试了许多方法来确保我可以在不显式指定类型的情况下调用fettTypes,并且仍然确保该函数返回的方法只接受{a:字符串}或{b:字符串},而不是{a:字符串;x:字符串}或{b:字符串;x:数字},但无济于事。
Is there any way I can accomplish this without requiring explicit specifying generic types for extractTypes
?
有没有什么方法可以在不要求显式指定提取类型的泛型类型的情况下实现这一点?
I think I need to find a way to create a type by subtracting one type (XType
) from another (Props
). I've tried using Omit<Props, keyof XType<T>>
but it doesn't work well here.
我想我需要找到一种方法,通过从一个类型(XType)中减去另一个类型(道具)来创建一个类型。我试过使用omit
>,但在这里不能很好地工作。
Thanks!
谢谢!
Asim
ASIM
更多回答
优秀答案推荐
I would simply extend XType
. This will force you to assert a type internally though.
我只需扩展XType即可。但这将迫使您在内部断言一个类型。
// adding a default for convenience
type XType<T = unknown> = {
x: T;
};
function extractTypes<Props extends XType>(Component: React.FC<Props>) {
// simply index and omit keys in `Props`
return (props: Omit<Props, keyof XType>, value: Props['x']) => {
Component({ ...(props as Props), x: value });
// assertion --------------
};
}
playground
操场
If you want excess property checking to also work when you pass a reference as props, you can use Omit<Props, keyof XType> & {[k in keyof XType]?: never}
but this may be overkill given the way people use React.
如果希望在将引用作为道具传递时,额外的属性检查也起作用,可以使用omit
&{[k in key of XType]?:ever},但考虑到人们使用Reaction的方式,这可能有些过分了。
As a side-note, merging the 2 generics was not strictly necessary and your original design is safer, because removing x: value
will yield an error
顺便提一下,合并这两个泛型并不是绝对必要的,而且您的原始设计更安全,因为删除x:Value会产生错误
function extractTypes<Props, T>(Component: React.FC<Props & XType<T>>) {
return (props: Omit<Props, keyof XType>, value: T) => {
Component({ ...(props as Props), x: value });
// assertion ---------------
};
}
I don't know why though because Props
is inferred as {a: string} & XType<string
我不知道为什么,因为道具被推断为{a:字符串}&XType<字符串
更多回答
I can use the necessary assertion as suggested, but it also works for { ...props } as Props
and even { } as Props
. This is fine since I have control of this piece of code. But I want to know how can I properly use typescript such that I don't need to use such potentially code-breaking assertions. =/
我可以按照建议使用必要的断言,但它也适用于{...道具}作为道具,甚至{}作为道具。这很好,因为我已经控制了这段代码。但我想知道我如何正确地使用打字脚本,这样我就不需要使用这种潜在的代码破解断言。=/
Also, this is an over-simplified example. The requirement is to be able to infer the type of T
used with XType
. In my actual code, it has a function which accepts a parameter of type T
. The second requirement is to be able to infer the actual type of props that were extended with XType
and used in React.FC<>
. I have a feeling that we should be able to infer these types within the function somehow.
此外,这也是一个过于简化的例子。要求能够推断XType使用的T的类型。在我的实际代码中,它有一个接受T类型参数的函数。第二个要求是能够推断使用XType扩展并在React.FC<>中使用的道具的实际类型。我有一种感觉,我们应该能够以某种方式在函数中推断出这些类型。
I was a bit pessimistic with my assertion. It's possible to only assert Props
on props
. When doing so, your original design with 2 generics works better. Try and experiment with your real use case. I don't like having multiple generics when I can avoid it but it does seem to help here.
我对我的断言有点悲观。可以只在props上断言Props。当这样做时,你的原始设计与2泛型工作得更好。尝试并试验您的真实用例。我不喜欢有多个泛型时,我可以避免它,但它似乎在这里帮助。
我是一名优秀的程序员,十分优秀!