【发布时间】:2021-08-10 19:05:43
【问题描述】:
我有一个通用的 React 函数组件,其中 T extends ReactText | boolean,它的 props 包含一个返回 T 的方法。
import React, { FC, ReactText } from 'react';
interface Thing {}
interface Props<T extends ReactText | boolean> {
value: T | null;
mapValues(thing: Thing): T;
}
interface MyComponent<T extends ReactText | boolean> extends FC<Props<T>> {}
function MyComponent<T extends ReactText | boolean>(
{ value, mapValues }: Props<T>
) {
// do stuff
return <div />;
}
但是,我想强制该方法返回 ReactText 和 boolean 之一;它也不能是返回的函数。
import React, { FC, ReactText } from 'react';
interface Thing {
someBool: boolean;
someStr: string;
}
interface Props<T extends ReactText | boolean> {
value:
boolean extends T ? boolean | null :
ReactText extends T ? ReactText | null :
never;
mapValues(thing: Thing):
boolean extends T ? boolean :
ReactText extends T ? ReactText :
never;
things: Thing[];
}
interface MyComponent<T extends ReactText | boolean> extends FC<Props<T>> {}
function MyComponent<T extends ReactText | boolean>(
{ value, mapValues, things }: Props<T>
) {
if (value != null) {
return <div>{value}</div>;
}
// super simplified verison of what I'm actually doing
const items = things
.map(mapValues)
.map(v => <li key={v.toString() /** assume v is unique */}>{v}</li>);
return <ul>{items}</ul>;
}
虽然非常丑陋,但它确实有效(在 TS Playground 中写出来后让我很惊讶)。
const things: Thing[] = [
{ someStr: 'a', someBool: false },
{ someStr: 'b', someBool: true }
];
const value = null;
const mapValues = (thing: Thing) =>
things.find(t => t.someStr === thing.someStr)?.someStr ??
things.find(t => t.someBool === thing.someBool)?.someBool ??
false;
// succeeds but is ugly and potentially fragile
// @ts-expect-error
<MyComponent things={things} value={value} mapValues={mapValues} />;
// this one works
// I don't know why `as ReactText` is needed when `ReactText` is `string | number`.
<MyComponent things={things} value={'abc' as ReactText} mapValues={() => 'abc' as ReactText} />;
Type '(thing: Thing) => string | boolean' is not assignable to type '(thing: Thing) => boolean'. Type 'string | boolean' is not assignable to type 'boolean'. Type 'string' is not assignable to type 'boolean'.
不过,我无法想象这是最好的解决方案。它很冗长,感觉很脆弱。
是否存在不是based on interface properties 的XOR 类型,因为这在这种情况下不起作用?也许使用Extract<T, U>?
【问题讨论】:
-
您能否展示一些应该有效的用法示例(而不仅仅是那些出错的示例),以便我们测试解决方案是否支持您的用例?
-
@jcalz 我更新了操场和代码 sn-p。
-
this 是否满足您的需求?玩弄它,让我知道。
-
@jcalz 是的,这确实有效。谢谢!
-
好的,有机会我可以写一个答案。
标签: typescript