作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图在 carbon-components-react 上修复一些关于 DataTable 的类型,但被困在使一个属性可选。我到了创建自己的演示来展示这个问题的地步:
import React from "react";
interface Human {
name: string;
age: number;
address?: string;
}
interface ButtonProps<R extends Human> {
name: R["name"];
age: R["age"];
address?: R["address"];
onClick?: Function;
}
interface RenderProps<R extends Human> {
human: R;
getButtonProps(data?: ButtonProps<R>): ButtonProps<R>;
}
export interface DataTableProps<R extends Human> {
rows: R[];
render(props: RenderProps<R>): React.ReactNode;
}
class DataTable<R extends Human> extends React.Component<DataTableProps<R>> {
render() {
return this.props.rows.map((h) => {
const buttonProps: () => Human = () => ({ ...h }); // This is only to be able to see the type of buttonProps in IDE
return this.props.render({ human: h, getButtonProps: buttonProps });
});
}
}
interface TableButtonProps {
name: string;
address?: string;
}
const TableButton = (props: TableButtonProps) => (
<button>Button for {props.name}</button>
);
export const Demo = () => {
// This works
const man1: Human = {
name: "Anna",
age: 30,
};
// This seems to be ok since "address" is optional
// but this isn't working!
const man2 = {
name: "Tom",
age: 32,
};
// This works
const man3 = {
name: "John",
age: 40,
address: "404 Street Unknown",
};
return (
<DataTable
rows={[man2]}
render={({ getButtonProps }) => {
return <TableButton {...getButtonProps()} />;
}}
></DataTable>
);
};
Type '{ name: string; age: number; address?: unknown; onClick?: Function | undefined; }' is not assignable to type 'TableButtonProps'.
Types of property 'address' are incompatible.
Type 'unknown' is not assignable to type 'string | undefined'.
Type 'unknown' is not assignable to type 'string'. TS2322
address
属性(property)有
unknown
出于某种原因键入。当我使用像
man1
这样的语法时或
man3
一切正常,您可以在
rows=
更换它.为什么是
man2
即使类型仍然设置为扩展 Human 也不起作用? TypeScript 会迷路吗?
npx create-react-app mydemo --template=typescript
初始化项目来测试这一点。
interface ButtonProps<R extends Human> {
name: Human["name"];
age: Human["age"];
address?: Human["address"];
onClick?: Function;
}
address
类型。
最佳答案
您可能已经注意到问题出在 address
属性(property)。
出于某种原因,它被推断为 unknown
.
通常,您会收到 unknown
因为 TS 无法推断通用参数。
见示例:
const foo = <T,>(arg: T): T => arg
// const foo: <unknown>(arg: unknown) => unknown
const result = foo() // unknown
考虑这个例子:
type GetAddress<T extends Human> = T extends Human ? T['address'] : never
type Result = GetAddress<{ name: 'John', age: 42 }> // unknown
从技术上讲,
{ name: 'John', age: 42 }
可分配给
Human
因为
address
是可选的。另一方面,
T['address']
不能退货
undefined
因为它不是 javascript - 它是 typescript 的(斯巴达)类型系统。因此,如果 TS 无法获取/推断
address
属性,最安全的选择是返回
unknown
;
Component
替换了内置的 react 组件类(class):
import React from "react";
interface Human {
name: string;
age: number;
address?: string;
}
interface ButtonProps<R extends Human> {
name: R["name"];
age: R["age"];
address?: R["address"];
onClick?: Function;
}
interface RenderProps<R extends Human> {
human: R;
getButtonProps(data?: ButtonProps<R>): ButtonProps<R>;
}
export interface DataTableProps<R extends Human, Address extends Human['address']> {
rows: R[];
render: (props: RenderProps<R>) => React.ReactNode;
}
class Component<Props>{
constructor(public props: Props) {
this.props = props
}
}
class Foo<T extends Human> extends Component<DataTableProps<T, T['address']>>{
render = () => {
return this.props.rows.map(
(row) =>
this
.props
.render(
{ human: row, getButtonProps: () => ({ ...row }) }
)
);
}
}
const human = { age: 42, name: 'John Doe' }
const jsx = new Foo({
rows: [human],
render: ({ getButtonProps }) => {
const x = getButtonProps().address
return <TableButton {...getButtonProps()} />;
}
})
请在此行抢夺
Component<DataTableProps<T, T['address']>>
我特意加了
T['address']
向您展示 TS 将如何推断它。
{age: number, name: string, address: unknown}
不能分配给
Human
因为
address
.
const human: Human = { age: 42, name: 'John Doe' }
这是因为没有显式类型,
R
推断为
{age: number, name: string}
而显式
Human
类型它被推断为
{age:number, name: string, address?:string, onClick?:Function}
.
DataTable
提供明确的通用参数。类(class)。
<DataTable<Human> // <---------------- fix is here
rows={[man2]}
render={({ getButtonProps }) => {
return <TableButton {...getButtonProps()} />;
}}
></DataTable>
顺便说一句,非常有趣的问题。
/**
* Replace all unknown props with appropriate Human props
*/
type HandleProps<T extends Human> = T & Omit<Human, keyof T>
// ............
class DataTable<R extends Human> extends React.Component<DataTableProps<HandleProps<R>>> {
render() {
return this.props.rows.map((h) => {
const buttonProps: () => Human = () => ({ ...h });
return this.props.render({ human: h, getButtonProps: buttonProps });
});
}
}
Playground
unknown
合适的 Prop
Human
Prop
关于reactjs - 为什么在使用泛型的特定设置中将可选字段的类型设置为未知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61069106/
我是一名优秀的程序员,十分优秀!