![](/img/trans.png)
[英]How do I infer the exact type of an object function parameter in TypeScript?
[英]Typescript: Infer lookup type for function parameter within object
定义通用表。 这需要数据和显示方式的架构。 这是如何调用它的简化示例。
<PagedTable
data={[ username: 'rob', logins: 32 ]}
schema={[
{
key: 'username',
customRender: (targetData, row) => fnThatOnlyTakesStrings(targetData)
}
]}
/>
组件类具有以下签名:
class PagedTable<T> extends Component<Props<T>, any>
和道具:
interface Props<T> {
data: T[] | null | undefined
schema: ColumnDef<T>[]
}
interface ColumnDef<T> {
key?: keyof T
customRender?: <U extends keyof T>(
targetData: T[U],
rowData: T
) => string | JSX.Element
}
因此,可以正确推断该类的具体类型。
为了完整起见,在PagedTable内部,该单元格的简化呈现功能是:
renderCell(datum: T, { customRender, key }: ColumnDef<T>) {
if (customRender) {
return customRender(datum[key!], datum, key!)
} else {
return datum[key]
}
}
我想要的是使targetData
在使用customRender函数时获取正确的类型。 在此设置中,其类型为number | string
number | string
不正确。
有没有一种方法可以仅使用架构对象的key
属性(保证是数据对象的键)来推断类型?
我认为您的主要问题是您可能不希望customRender
成为通用函数。 并非任何customRender
都可以为任何 U
取T[U]
,而是每个customRender
希望有一个特定的 U
毕竟, (targetData, row) => fnThatOnlyTakesStrings(targetData)
似乎期望targetData
是一个string
,它仅适用于某些特定键,对吗?
因此,我认为您确实希望ColumnDef
在T
和U
中都是通用的,如下所示:
interface ColumnDef<T, U extends keyof T> {
key?: U
customRender?: (
targetData: T[U],
rowData: T
) => string | JSX.Element
}
这最终需要传播到引用ColumnDef
其他事物:
interface Props<T, U extends keyof T> {
data: T[] | null | undefined
schema: ColumnDef<T, U>[]
}
class PagedTable<T, U extends keyof T> extends React.Component<Props<T, U>, any> {
renderCell(datum: T, cd: ColumnDef<T, U>) {
if (cd.customRender) {
return cd.customRender(datum[cd.key! as any as U], datum)
} else {
return datum[cd.key!]
}
}
}
(我不确定对renderCell
所做的更改是否必要或是否符合预期,但是我遇到了与参数数量有关的错误,并且我对其进行了修复,直到没有抱怨为止。您应该对其进行更改以适合您的需求)。
希望能有所帮助。 祝好运。
如果我正确理解这一点,那么棘手的方面是schema
可以具有多个不同类型的ColumnDef
,并且每个 ColumnDef
的键都需要与其customRender
函数相对应。 为了让TypeScript为每个ColumnDef
推断并强制使用不同的类型,您需要将每个ColumnDef
包装在函数调用中。 然后我发现我需要显式指定T
以便推理起作用。 希望不会有麻烦,因为我认为在实际应用程序中您已经具有T
类型定义。 这段代码为我工作:
import * as React from "react";
interface Props<T> {
data: T[] | null | undefined
schema: WrappedColumnDef<T>[]
}
interface ColumnDef<T, U extends keyof T> {
key?: U
customRender?: (
targetData: T[U],
rowData: T
) => string | JSX.Element
}
const WRAPPED_COLUMN_DEF_MARKER = Symbol();
interface WrappedColumnDef<T> extends ColumnDef<T, any> {
[WRAPPED_COLUMN_DEF_MARKER]: undefined;
}
declare function wrapColumnDef<T, U extends keyof T>(arg: ColumnDef<T, U>): WrappedColumnDef<T> {
return arg as WrappedColumnDef<T>;
}
declare class PagedTable<T> extends React.Component<Props<T>, any> {}
declare function fnThatOnlyTakesStrings(arg: string): string;
interface MyDatum {
username: string;
logins: number;
}
let x = <PagedTable<MyDatum>
data={[{ username: 'rob', logins: 32 }]}
schema={[
wrapColumnDef({
key: 'username',
customRender: (targetData, row) => fnThatOnlyTakesStrings(targetData)
})
]}
/>;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.