Typescript 具有泛型类型并使用字符串作为默认参数的函数

Typescript 具有泛型类型并使用字符串作为默认参数的函数,typescript,typescript-generics,Typescript,Typescript Generics,我有一个将对象作为通用输入的函数,我希望通过将通用T设置为字符串来提供一个默认实现,并使用默认值提供所需的参数,而该默认值使用字符串 type Props<T> = { items: T[]; renderItem: (item: T) => JSX.Element; }; const defaultRenderItem = (item: string) => item; const defaultItems = ['1', '2']; function re

我有一个将对象作为通用输入的函数,我希望通过将通用
T
设置为字符串来提供一个默认实现,并使用默认值提供所需的参数,而该默认值使用字符串

type Props<T> = {
  items: T[];
  renderItem: (item: T) => JSX.Element;
};

const defaultRenderItem = (item: string) => item;
const defaultItems = ['1', '2'];

function render<T>({ items = defaultItems, renderItem = defaultRenderItem }: Props<T>) {
  return items.map(renderItem);
}
类型道具={
项目:T[];;
renderItem:(item:T)=>JSX.Element;
};
常量defaultRenderItem=(项:字符串)=>项;
const defaultItems=['1','2'];
函数render({items=defaultItems,renderItem=defaultRenderItem}:Props){
返回项目.map(renderItem);
}
您可以检查此代码的运行示例

问题是typescript抱怨说,
'T'可以用与“string.ts(2322)

我确实理解typescript的担忧,是否有人能告诉我或提供一个替代方案,说明我如何在没有错误的情况下实现相同的结果

您可以在函数的实现端解决错误,但我认为您希望防止有人调用以下内容:

render({ renderItem: (x: number) => x - 2 });
这将导致运行时错误,但编译器会很高兴地推断出
T
number
,并假装一切正常


为了解决这个问题,我认为我们应该放弃在调用签名本身中使用默认值,而使用它来表示两种不同的调用情况:如果您传递了一个不完整的
Props
,那么它必须是
Props
。否则,如果您传递一个完整的
道具
,您可以使用任何您想要的泛型类型,只要它匹配。我们将在实现中处理默认值。可能是这样的:

function render(stringProps: Partial<Props<string>>): string[];
function render<T>(otherProps: Props<T>): T[];
function render(props: Partial<Props<any>>) {
    const items = props.items || defaultItems;
    const renderItem = props.renderItem || defaultRenderItem;
    return items.map(renderItem);
}
如果你试图调用
render()
,但有一些东西不完整,编译器现在会对你大喊大叫,除非不完整的东西与在通用版本中选择
string
as
T
一致。希望这能给你足够的时间来工作。祝你好运


我可以假设您希望能够调用
render({})
?或者如果需要默认值,是否需要编写
render({items:undefined,renderItem:undefined})
?@jcalz是的,您可以假设我希望能够调用
render({})
// first overload, Partial<Props<string>> 
const a = render({}); // string[]
const b = render({ renderItem: x => x.toUpperCase() }); // okay, x must be string
// second overload, Props<T> for generic <T>
const c = render({ items: [1, 2, 3], renderItem: x => x - 2 }); // okay, d is number[]

// errors
const d = render<number>({}); // error! {} is not a Props<number>
const e = render({ renderItem: (x: number) => x - 2 }); // error! if you leave out a property, it must be string-typed 
const f = render({ items: [1, 2, 3], renderItem: (x: string) => x.toUpperCase() }); // error! mismatch types